synapse 2.221.0__py311-none-any.whl → 2.223.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 +143 -44
- synapse/cryotank.py +1 -1
- synapse/data/lark/storm.lark +9 -6
- synapse/lib/ast.py +13 -5
- synapse/lib/layer.py +18 -11
- synapse/lib/nexus.py +1 -1
- synapse/lib/parser.py +1 -0
- synapse/lib/rstorm.py +19 -1
- synapse/lib/schemas.py +4 -0
- synapse/lib/snap.py +15 -9
- synapse/lib/storm.py +0 -190
- synapse/lib/stormlib/auth.py +1 -1
- synapse/lib/stormlib/cortex.py +1 -1
- synapse/lib/stormlib/mime.py +15 -5
- synapse/lib/stormlib/pkg.py +598 -0
- synapse/lib/stormlib/task.py +115 -0
- synapse/lib/stormtypes.py +42 -178
- synapse/lib/trigger.py +16 -14
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +17 -14
- synapse/models/files.py +1 -1
- synapse/models/orgs.py +3 -0
- synapse/tests/test_cortex.py +1 -1
- synapse/tests/test_lib_aha.py +68 -53
- synapse/tests/test_lib_ast.py +3 -0
- synapse/tests/test_lib_cell.py +12 -12
- synapse/tests/test_lib_grammar.py +4 -4
- synapse/tests/test_lib_rstorm.py +55 -7
- synapse/tests/test_lib_storm.py +105 -249
- synapse/tests/test_lib_stormlib_auth.py +84 -0
- synapse/tests/test_lib_stormlib_cortex.py +1 -0
- synapse/tests/test_lib_stormlib_mime.py +24 -0
- synapse/tests/test_lib_stormlib_pkg.py +456 -0
- synapse/tests/test_lib_stormlib_task.py +98 -0
- synapse/tests/test_lib_stormtypes.py +25 -100
- synapse/tests/test_lib_trigger.py +66 -3
- synapse/tests/test_lib_view.py +53 -0
- synapse/tests/test_model_files.py +11 -0
- synapse/tests/test_model_orgs.py +6 -1
- synapse/tools/cryo/cat.py +2 -1
- synapse/tools/cryo/list.py +2 -0
- {synapse-2.221.0.dist-info → synapse-2.223.0.dist-info}/METADATA +1 -1
- {synapse-2.221.0.dist-info → synapse-2.223.0.dist-info}/RECORD +46 -42
- {synapse-2.221.0.dist-info → synapse-2.223.0.dist-info}/WHEEL +0 -0
- {synapse-2.221.0.dist-info → synapse-2.223.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.221.0.dist-info → synapse-2.223.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py
CHANGED
|
@@ -61,6 +61,7 @@ import synapse.lib.stormlib.gen as s_stormlib_gen # NOQA
|
|
|
61
61
|
import synapse.lib.stormlib.gis as s_stormlib_gis # NOQA
|
|
62
62
|
import synapse.lib.stormlib.hex as s_stormlib_hex # NOQA
|
|
63
63
|
import synapse.lib.stormlib.log as s_stormlib_log # NOQA
|
|
64
|
+
import synapse.lib.stormlib.pkg as s_stormlib_pkg # NOQA
|
|
64
65
|
import synapse.lib.stormlib.xml as s_stormlib_xml # NOQA
|
|
65
66
|
import synapse.lib.stormlib.auth as s_stormlib_auth # NOQA
|
|
66
67
|
import synapse.lib.stormlib.cell as s_stormlib_cell # NOQA
|
|
@@ -72,6 +73,7 @@ import synapse.lib.stormlib.mime as s_stormlib_mime # NOQA
|
|
|
72
73
|
import synapse.lib.stormlib.pack as s_stormlib_pack # NOQA
|
|
73
74
|
import synapse.lib.stormlib.smtp as s_stormlib_smtp # NOQA
|
|
74
75
|
import synapse.lib.stormlib.stix as s_stormlib_stix # NOQA
|
|
76
|
+
import synapse.lib.stormlib.task as s_stormlib_task # NOQA
|
|
75
77
|
import synapse.lib.stormlib.yaml as s_stormlib_yaml # NOQA
|
|
76
78
|
import synapse.lib.stormlib.basex as s_stormlib_basex # NOQA
|
|
77
79
|
import synapse.lib.stormlib.cache as s_stormlib_cache # NOQA
|
|
@@ -624,7 +626,8 @@ class CoreApi(s_cell.CellApi):
|
|
|
624
626
|
Returns:
|
|
625
627
|
AsyncIterator[Tuple(buid, valu)]
|
|
626
628
|
'''
|
|
627
|
-
self.user.
|
|
629
|
+
if not self.user.allowed(('layer', 'lift', layriden)):
|
|
630
|
+
self.user.confirm(('layer', 'read', layriden))
|
|
628
631
|
async for item in self.cell.iterFormRows(layriden, form, stortype=stortype, startvalu=startvalu):
|
|
629
632
|
yield item
|
|
630
633
|
|
|
@@ -642,7 +645,8 @@ class CoreApi(s_cell.CellApi):
|
|
|
642
645
|
Returns:
|
|
643
646
|
AsyncIterator[Tuple(buid, valu)]
|
|
644
647
|
'''
|
|
645
|
-
self.user.
|
|
648
|
+
if not self.user.allowed(('layer', 'lift', layriden)):
|
|
649
|
+
self.user.confirm(('layer', 'read', layriden))
|
|
646
650
|
async for item in self.cell.iterPropRows(layriden, form, prop, stortype=stortype, startvalu=startvalu):
|
|
647
651
|
yield item
|
|
648
652
|
|
|
@@ -659,7 +663,8 @@ class CoreApi(s_cell.CellApi):
|
|
|
659
663
|
Returns:
|
|
660
664
|
AsyncIterator[Tuple(buid, valu)]
|
|
661
665
|
'''
|
|
662
|
-
self.user.
|
|
666
|
+
if not self.user.allowed(('layer', 'lift', layriden)):
|
|
667
|
+
self.user.confirm(('layer', 'read', layriden))
|
|
663
668
|
async for item in self.cell.iterUnivRows(layriden, prop, stortype=stortype, startvalu=startvalu):
|
|
664
669
|
yield item
|
|
665
670
|
|
|
@@ -680,7 +685,8 @@ class CoreApi(s_cell.CellApi):
|
|
|
680
685
|
This yields (buid, (tagvalu, form)) instead of just buid, valu in order to allow resuming an interrupted
|
|
681
686
|
call by feeding the last value retrieved into starttupl
|
|
682
687
|
'''
|
|
683
|
-
self.user.
|
|
688
|
+
if not self.user.allowed(('layer', 'lift', layriden)):
|
|
689
|
+
self.user.confirm(('layer', 'read', layriden))
|
|
684
690
|
async for item in self.cell.iterTagRows(layriden, tag, form=form, starttupl=starttupl):
|
|
685
691
|
yield item
|
|
686
692
|
|
|
@@ -699,7 +705,8 @@ class CoreApi(s_cell.CellApi):
|
|
|
699
705
|
Returns:
|
|
700
706
|
AsyncIterator[Tuple(buid, valu)]
|
|
701
707
|
'''
|
|
702
|
-
self.user.
|
|
708
|
+
if not self.user.allowed(('layer', 'lift', layriden)):
|
|
709
|
+
self.user.confirm(('layer', 'read', layriden))
|
|
703
710
|
async for item in self.cell.iterTagPropRows(layriden, tag, prop, form=form, stortype=stortype,
|
|
704
711
|
startvalu=startvalu):
|
|
705
712
|
yield item
|
|
@@ -1366,6 +1373,30 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
1366
1373
|
|
|
1367
1374
|
def _initCorePerms(self):
|
|
1368
1375
|
self._cortex_permdefs.extend((
|
|
1376
|
+
{'perm': ('axon', 'upload'), 'gate': 'cortex',
|
|
1377
|
+
'desc': 'Controls the ability to upload a file to the Axon.'},
|
|
1378
|
+
{'perm': ('axon', 'get'), 'gate': 'cortex',
|
|
1379
|
+
'desc': 'Controls the ability to retrieve a file from the Axon.'},
|
|
1380
|
+
{'perm': ('axon', 'has'), 'gate': 'cortex',
|
|
1381
|
+
'desc': 'Controls the ability to check if the Axon contains a file.'},
|
|
1382
|
+
{'perm': ('axon', 'del'), 'gate': 'cortex',
|
|
1383
|
+
'desc': 'Controls the ability to remove a file from the Axon.'},
|
|
1384
|
+
|
|
1385
|
+
{'perm': ('layer', 'add'), 'gate': 'cortex',
|
|
1386
|
+
'desc': 'Controls the ability to add Layers to the cortex.'},
|
|
1387
|
+
{'perm': ('layer', 'del'), 'gate': 'cortex',
|
|
1388
|
+
'desc': 'Controls the ability to remove Layers from the cortex.'},
|
|
1389
|
+
{'perm': ('layer', 'read'), 'gate': 'layer',
|
|
1390
|
+
'desc': 'Controls the ability to read/lift from a Layer.'},
|
|
1391
|
+
{'perm': ('layer', 'read', '<iden>'), 'gate': 'cortex',
|
|
1392
|
+
'desc': 'Controls the ability to read/lift from a specific Layer.'},
|
|
1393
|
+
{'perm': ('layer', 'set', '<name>'), 'gate': 'layer',
|
|
1394
|
+
'desc': 'Controls the ability to configure properties of a Layer.'},
|
|
1395
|
+
{'perm': ('layer', 'write'), 'gate': 'layer',
|
|
1396
|
+
'desc': 'Controls the ability to write to a Layer.'},
|
|
1397
|
+
{'perm': ('layer', 'write', '<iden>'), 'gate': 'cortex',
|
|
1398
|
+
'desc': 'Controls the ability to write to a specific Layer.'},
|
|
1399
|
+
|
|
1369
1400
|
{'perm': ('model', 'form', 'add'), 'gate': 'cortex',
|
|
1370
1401
|
'desc': 'Controls access to adding extended model forms.'},
|
|
1371
1402
|
{'perm': ('model', 'form', 'add', '<form>'), 'gate': 'cortex',
|
|
@@ -1519,15 +1550,6 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
1519
1550
|
{'perm': ('view', 'set', '<setting>'), 'gate': 'view',
|
|
1520
1551
|
'desc': 'Controls access to change view settings.',
|
|
1521
1552
|
'ex': 'view.set.name'},
|
|
1522
|
-
|
|
1523
|
-
{'perm': ('axon', 'upload'), 'gate': 'cortex',
|
|
1524
|
-
'desc': 'Controls the ability to upload a file to the Axon.'},
|
|
1525
|
-
{'perm': ('axon', 'get'), 'gate': 'cortex',
|
|
1526
|
-
'desc': 'Controls the ability to retrieve a file from the Axon.'},
|
|
1527
|
-
{'perm': ('axon', 'has'), 'gate': 'cortex',
|
|
1528
|
-
'desc': 'Controls the ability to check if the Axon contains a file.'},
|
|
1529
|
-
{'perm': ('axon', 'del'), 'gate': 'cortex',
|
|
1530
|
-
'desc': 'Controls the ability to remove a file from the Axon.'},
|
|
1531
1553
|
))
|
|
1532
1554
|
for pdef in self._cortex_permdefs:
|
|
1533
1555
|
s_schemas.reqValidPermDef(pdef)
|
|
@@ -2242,6 +2264,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2242
2264
|
self.onfini(slab.fini)
|
|
2243
2265
|
|
|
2244
2266
|
self.multiqueue = await slab.getMultiQueue('cortex:queue', nexsroot=self.nexsroot)
|
|
2267
|
+
self.stormpkgqueue = await slab.getMultiQueue('storm:pkg:queue', nexsroot=self.nexsroot)
|
|
2245
2268
|
|
|
2246
2269
|
async def _initStormGraphs(self):
|
|
2247
2270
|
path = os.path.join(self.dirn, 'slabs', 'graphs.lmdb')
|
|
@@ -3042,8 +3065,8 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3042
3065
|
if not ok:
|
|
3043
3066
|
break
|
|
3044
3067
|
|
|
3045
|
-
curvers = vers
|
|
3046
|
-
await self.setStormPkgVar(name, varname,
|
|
3068
|
+
curvers = max(vers, await self.getStormPkgVar(name, varname, default=-1))
|
|
3069
|
+
await self.setStormPkgVar(name, varname, curvers)
|
|
3047
3070
|
logger.info(f'{name} finished init vers={vers}: {vname}', extra=logextra)
|
|
3048
3071
|
|
|
3049
3072
|
if onload is not None:
|
|
@@ -3328,6 +3351,91 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3328
3351
|
for item in pkgvars.items():
|
|
3329
3352
|
yield item
|
|
3330
3353
|
|
|
3354
|
+
async def addStormPkgQueue(self, pkgname, name):
|
|
3355
|
+
guid = s_common.guid((pkgname, name))
|
|
3356
|
+
if self.stormpkgqueue.exists(guid):
|
|
3357
|
+
mesg = f'Queue named {name} already exists for package {pkgname}!'
|
|
3358
|
+
raise s_exc.DupName(mesg=mesg)
|
|
3359
|
+
|
|
3360
|
+
info = {
|
|
3361
|
+
'iden': guid,
|
|
3362
|
+
'name': name,
|
|
3363
|
+
'pkgname': pkgname,
|
|
3364
|
+
'created': s_common.now()
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
await self._push('storm:pkg:queue:add', pkgname, name, info)
|
|
3368
|
+
|
|
3369
|
+
@s_nexus.Pusher.onPush('storm:pkg:queue:add')
|
|
3370
|
+
async def _addStormPkgQueue(self, pkgname, name, info):
|
|
3371
|
+
guid = s_common.guid((pkgname, name))
|
|
3372
|
+
if self.stormpkgqueue.exists(guid):
|
|
3373
|
+
return
|
|
3374
|
+
await self.stormpkgqueue.add(guid, info)
|
|
3375
|
+
|
|
3376
|
+
async def listStormPkgQueues(self, pkgname=None):
|
|
3377
|
+
for pkginfo in self.stormpkgqueue.list():
|
|
3378
|
+
if pkgname is None or pkginfo['meta'].get('pkgname') == pkgname:
|
|
3379
|
+
yield pkginfo
|
|
3380
|
+
|
|
3381
|
+
async def getStormPkgQueue(self, pkgname, name):
|
|
3382
|
+
guid = s_common.guid((pkgname, name))
|
|
3383
|
+
return self.stormpkgqueue.status(guid)
|
|
3384
|
+
|
|
3385
|
+
async def delStormPkgQueue(self, pkgname, name):
|
|
3386
|
+
guid = s_common.guid((pkgname, name))
|
|
3387
|
+
if not self.stormpkgqueue.exists(guid):
|
|
3388
|
+
mesg = f'No queue named {name} exists for package {pkgname}!'
|
|
3389
|
+
raise s_exc.NoSuchName(mesg=mesg)
|
|
3390
|
+
|
|
3391
|
+
await self._push('storm:pkg:queue:del', pkgname, name)
|
|
3392
|
+
|
|
3393
|
+
@s_nexus.Pusher.onPush('storm:pkg:queue:del')
|
|
3394
|
+
async def _delStormPkgQueue(self, pkgname, name):
|
|
3395
|
+
guid = s_common.guid((pkgname, name))
|
|
3396
|
+
if not self.stormpkgqueue.exists(guid):
|
|
3397
|
+
return
|
|
3398
|
+
await self.stormpkgqueue.rem(guid)
|
|
3399
|
+
|
|
3400
|
+
async def stormPkgQueueGet(self, pkgname, name, offs=0, wait=False):
|
|
3401
|
+
guid = s_common.guid((pkgname, name))
|
|
3402
|
+
async for item in self.stormpkgqueue.gets(guid, offs, cull=False, wait=wait):
|
|
3403
|
+
return item
|
|
3404
|
+
|
|
3405
|
+
async def stormPkgQueueGets(self, pkgname, name, offs=0, wait=False, size=None):
|
|
3406
|
+
count = 0
|
|
3407
|
+
guid = s_common.guid((pkgname, name))
|
|
3408
|
+
async for item in self.stormpkgqueue.gets(guid, offs, cull=False, wait=wait):
|
|
3409
|
+
|
|
3410
|
+
yield item
|
|
3411
|
+
|
|
3412
|
+
count += 1
|
|
3413
|
+
if size is not None and count >= size:
|
|
3414
|
+
return
|
|
3415
|
+
|
|
3416
|
+
async def stormPkgQueuePuts(self, pkgname, name, items):
|
|
3417
|
+
return await self._push('storm:pkg:queue:puts', pkgname, name, items)
|
|
3418
|
+
|
|
3419
|
+
@s_nexus.Pusher.onPush('storm:pkg:queue:puts', passitem=True)
|
|
3420
|
+
async def _stormPkgQueuePuts(self, pkgname, name, items, nexsitem):
|
|
3421
|
+
nexsoff, nexsmesg = nexsitem
|
|
3422
|
+
guid = s_common.guid((pkgname, name))
|
|
3423
|
+
return await self.stormpkgqueue.puts(guid, items, reqid=nexsoff)
|
|
3424
|
+
|
|
3425
|
+
@s_nexus.Pusher.onPushAuto('storm:pkg:queue:cull')
|
|
3426
|
+
async def stormPkgQueueCull(self, pkgname, name, offs):
|
|
3427
|
+
guid = s_common.guid((pkgname, name))
|
|
3428
|
+
await self.stormpkgqueue.cull(guid, offs)
|
|
3429
|
+
|
|
3430
|
+
@s_nexus.Pusher.onPushAuto('storm:pkg:queue:pop')
|
|
3431
|
+
async def stormPkgQueuePop(self, pkgname, name, offs):
|
|
3432
|
+
guid = s_common.guid((pkgname, name))
|
|
3433
|
+
return await self.stormpkgqueue.pop(guid, offs)
|
|
3434
|
+
|
|
3435
|
+
async def stormPkgQueueSize(self, pkgname, name):
|
|
3436
|
+
guid = s_common.guid((pkgname, name))
|
|
3437
|
+
return self.stormpkgqueue.size(guid)
|
|
3438
|
+
|
|
3331
3439
|
async def _cortexHealth(self, health):
|
|
3332
3440
|
health.update('cortex', 'nominal')
|
|
3333
3441
|
|
|
@@ -4548,34 +4656,25 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4548
4656
|
self.addStormCmd(s_stormlib_cortex.StormPoolGetCmd)
|
|
4549
4657
|
self.addStormCmd(s_stormlib_cortex.StormPoolSetCmd)
|
|
4550
4658
|
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
for cdef in
|
|
4570
|
-
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4571
|
-
|
|
4572
|
-
for cdef in s_stormlib_cortex.stormcmds:
|
|
4573
|
-
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4574
|
-
|
|
4575
|
-
for cdef in s_stormlib_vault.stormcmds:
|
|
4576
|
-
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4577
|
-
|
|
4578
|
-
for cdef in s_stormlib_index.stormcmds:
|
|
4659
|
+
cmdmods = [
|
|
4660
|
+
s_storm,
|
|
4661
|
+
s_stormsvc,
|
|
4662
|
+
s_stormlib_aha,
|
|
4663
|
+
s_stormlib_auth,
|
|
4664
|
+
s_stormlib_cortex,
|
|
4665
|
+
s_stormlib_gen,
|
|
4666
|
+
s_stormlib_index,
|
|
4667
|
+
s_stormlib_macro,
|
|
4668
|
+
s_stormlib_model,
|
|
4669
|
+
s_stormlib_pkg,
|
|
4670
|
+
s_stormlib_vault,
|
|
4671
|
+
]
|
|
4672
|
+
|
|
4673
|
+
for cmod in cmdmods:
|
|
4674
|
+
for cdef in cmod.stormcmds:
|
|
4675
|
+
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4676
|
+
|
|
4677
|
+
for cdef in s_stormlib_task.stormcmds:
|
|
4579
4678
|
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4580
4679
|
|
|
4581
4680
|
async def _initPureStormCmds(self):
|
synapse/cryotank.py
CHANGED
|
@@ -39,7 +39,7 @@ class CryoTank(s_base.Base):
|
|
|
39
39
|
A CryoTank implements a stream of structured data.
|
|
40
40
|
'''
|
|
41
41
|
async def __anit__(self, dirn, iden, conf=None):
|
|
42
|
-
|
|
42
|
+
s_common.deprecated('synapse.cryotank.CryoTank', curv='2.223.0')
|
|
43
43
|
await s_base.Base.__anit__(self)
|
|
44
44
|
|
|
45
45
|
if conf is None:
|
synapse/data/lark/storm.lark
CHANGED
|
@@ -238,10 +238,10 @@ liftreverse: _REVERSE "(" (liftformtag | liftpropby | liftprop | liftbyarray | l
|
|
|
238
238
|
|
|
239
239
|
_DEREF.3: /\*(?=\$)/
|
|
240
240
|
|
|
241
|
-
liftformtag: (
|
|
242
|
-
liftpropby: (
|
|
243
|
-
liftprop: (
|
|
244
|
-
liftbyarray: (
|
|
241
|
+
liftformtag: (PROPS | UNIVNAME | WILDPROPS | derefprops) tagname [_cmpr _valu]
|
|
242
|
+
liftpropby: (PROPS | EMBEDPROPS | UNIVNAME | derefprops) _cmpr _valu
|
|
243
|
+
liftprop: (PROPS | UNIVNAME | WILDPROPS | derefprops)
|
|
244
|
+
liftbyarray: (PROPS | EMBEDPROPS | UNIVNAME | derefprops) "*[" _safe_cmpr _valu "]"
|
|
245
245
|
lifttagtag: (_HASH | _HASHSPACE) tagname [_cmpr _valu]
|
|
246
246
|
liftbytag: (tagname | tagnamewithspace) [_cmpr _valu]
|
|
247
247
|
liftbytagprop: (tagprop | tagpropwithspace) [_cmpr _valu]
|
|
@@ -249,7 +249,7 @@ liftbyformtagprop: formtagprop [_cmpr _valu]
|
|
|
249
249
|
|
|
250
250
|
tagprop: tagname _COLONNOSPACE (BASEPROP | _varvalu)
|
|
251
251
|
tagpropwithspace: tagnamewithspace _COLONNOSPACE (BASEPROP | _varvalu) -> tagprop
|
|
252
|
-
formtagprop: (
|
|
252
|
+
formtagprop: (PROPS | UNIVNAME | WILDPROPS | derefprops) tagname _COLONNOSPACE (BASEPROP | _varvalu)
|
|
253
253
|
_COLONNOSPACE.2: /(?<!\s):/
|
|
254
254
|
|
|
255
255
|
_funcarg: (VARTOKN [EQNOSPACE _valu])
|
|
@@ -484,7 +484,7 @@ EMBEDPROPS.2: /[a-z_][a-z0-9_]*(:[a-z0-9_]+)+((\:\:|\:|\.)[a-z0-9_]+)*(?![:.a-z0
|
|
|
484
484
|
UNIVNAME.2: /(?<=^|[\s\|\{\(\[+=-])\.[a-z_][a-z0-9_]*([:.][a-z0-9_]+)*/
|
|
485
485
|
univprop: UNIVNAME | "." _varvalu
|
|
486
486
|
// A full property or a universal property
|
|
487
|
-
formname: PROPS |
|
|
487
|
+
formname: PROPS | derefprops
|
|
488
488
|
// A relative property
|
|
489
489
|
relprop: RELNAME | _COLONDOLLAR _varvaluatom
|
|
490
490
|
|
|
@@ -494,6 +494,9 @@ RELNAME: /(?<!\w):\.?[a-z_][a-z0-9_]*(?:(\:\:|\:|\.)[a-z_][a-z0-9_]*)*/
|
|
|
494
494
|
// Similar to PROPS but does not require a colon
|
|
495
495
|
BASEPROP: /[a-z_][a-z0-9_]*(?:(\:\:|\:|\.)[a-z_][a-z0-9_]*)*/
|
|
496
496
|
|
|
497
|
+
// Derefed variable for prop names
|
|
498
|
+
derefprops: _DEREF _varvalu
|
|
499
|
+
|
|
497
500
|
// The entry point for a $(...) expression. The initial dollar sign is now optional
|
|
498
501
|
_dollarexprs: "$"? dollaroper
|
|
499
502
|
|
synapse/lib/ast.py
CHANGED
|
@@ -2,7 +2,6 @@ import types
|
|
|
2
2
|
import asyncio
|
|
3
3
|
import decimal
|
|
4
4
|
import fnmatch
|
|
5
|
-
import hashlib
|
|
6
5
|
import logging
|
|
7
6
|
import binascii
|
|
8
7
|
import itertools
|
|
@@ -1833,7 +1832,7 @@ class LiftProp(LiftOper):
|
|
|
1833
1832
|
|
|
1834
1833
|
assert len(self.kids) == 1
|
|
1835
1834
|
|
|
1836
|
-
name = await
|
|
1835
|
+
name = await self.kids[0].compute(runt, path)
|
|
1837
1836
|
|
|
1838
1837
|
prop = runt.model.props.get(name)
|
|
1839
1838
|
if prop is not None:
|
|
@@ -4029,6 +4028,13 @@ class FormName(Value):
|
|
|
4029
4028
|
async def compute(self, runt, path):
|
|
4030
4029
|
return await self.kids[0].compute(runt, path)
|
|
4031
4030
|
|
|
4031
|
+
class DerefProps(Value):
|
|
4032
|
+
async def compute(self, runt, path):
|
|
4033
|
+
valu = await toprim(await self.kids[0].compute(runt, path))
|
|
4034
|
+
if (exc := await s_stormtypes.typeerr(valu, str)) is not None:
|
|
4035
|
+
raise self.kids[0].addExcInfo(exc)
|
|
4036
|
+
return valu
|
|
4037
|
+
|
|
4032
4038
|
class RelProp(PropName):
|
|
4033
4039
|
pass
|
|
4034
4040
|
|
|
@@ -4521,9 +4527,6 @@ class N1Walk(Oper):
|
|
|
4521
4527
|
|
|
4522
4528
|
def buildfilter(self, runt, destforms, cmpr):
|
|
4523
4529
|
|
|
4524
|
-
if not isinstance(destforms, (tuple, list)):
|
|
4525
|
-
destforms = (destforms,)
|
|
4526
|
-
|
|
4527
4530
|
if '*' in destforms:
|
|
4528
4531
|
if cmpr is not None:
|
|
4529
4532
|
mesg = 'Wild card walk operations do not support comparison.'
|
|
@@ -4608,6 +4611,11 @@ class N1Walk(Oper):
|
|
|
4608
4611
|
dest = await self.kids[1].compute(runt, path)
|
|
4609
4612
|
dest = await s_stormtypes.toprim(dest)
|
|
4610
4613
|
|
|
4614
|
+
if isinstance(dest, (tuple, list)):
|
|
4615
|
+
dest = [await s_stormtypes.tostr(form) for form in dest]
|
|
4616
|
+
else:
|
|
4617
|
+
dest = (await s_stormtypes.tostr(dest),)
|
|
4618
|
+
|
|
4611
4619
|
destfilt = self.buildfilter(runt, dest, cmpr)
|
|
4612
4620
|
|
|
4613
4621
|
for verb in verbs:
|
synapse/lib/layer.py
CHANGED
|
@@ -119,6 +119,7 @@ class LayerApi(s_cell.CellApi):
|
|
|
119
119
|
|
|
120
120
|
self.layr = layr
|
|
121
121
|
self.liftperm = ('layer', 'lift', self.layr.iden)
|
|
122
|
+
self.readperm = ('layer', 'read', self.layr.iden)
|
|
122
123
|
self.writeperm = ('layer', 'write', self.layr.iden)
|
|
123
124
|
|
|
124
125
|
async def iterLayerNodeEdits(self):
|
|
@@ -126,7 +127,8 @@ class LayerApi(s_cell.CellApi):
|
|
|
126
127
|
Scan the full layer and yield artificial nodeedit sets.
|
|
127
128
|
'''
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
if not self.allowed(self.liftperm):
|
|
131
|
+
await self._reqUserAllowed(self.readperm)
|
|
130
132
|
async for item in self.layr.iterLayerNodeEdits():
|
|
131
133
|
yield item
|
|
132
134
|
await asyncio.sleep(0)
|
|
@@ -165,13 +167,15 @@ class LayerApi(s_cell.CellApi):
|
|
|
165
167
|
|
|
166
168
|
Once caught up with storage, yield them in realtime.
|
|
167
169
|
'''
|
|
168
|
-
|
|
170
|
+
if not self.allowed(self.liftperm):
|
|
171
|
+
await self._reqUserAllowed(self.readperm)
|
|
169
172
|
async for item in self.layr.syncNodeEdits(offs, wait=wait, reverse=reverse):
|
|
170
173
|
yield item
|
|
171
174
|
await asyncio.sleep(0)
|
|
172
175
|
|
|
173
176
|
async def syncNodeEdits2(self, offs, wait=True):
|
|
174
|
-
|
|
177
|
+
if not self.allowed(self.liftperm):
|
|
178
|
+
await self._reqUserAllowed(self.readperm)
|
|
175
179
|
async for item in self.layr.syncNodeEdits2(offs, wait=wait):
|
|
176
180
|
yield item
|
|
177
181
|
await asyncio.sleep(0)
|
|
@@ -180,18 +184,21 @@ class LayerApi(s_cell.CellApi):
|
|
|
180
184
|
'''
|
|
181
185
|
Returns what will be the *next* nodeedit log index.
|
|
182
186
|
'''
|
|
183
|
-
|
|
187
|
+
if not self.allowed(self.liftperm):
|
|
188
|
+
await self._reqUserAllowed(self.readperm)
|
|
184
189
|
return await self.layr.getEditIndx()
|
|
185
190
|
|
|
186
191
|
async def getEditSize(self):
|
|
187
192
|
'''
|
|
188
193
|
Return the total number of (edits, meta) pairs in the layer changelog.
|
|
189
194
|
'''
|
|
190
|
-
|
|
195
|
+
if not self.allowed(self.liftperm):
|
|
196
|
+
await self._reqUserAllowed(self.readperm)
|
|
191
197
|
return await self.layr.getEditSize()
|
|
192
198
|
|
|
193
199
|
async def getIden(self):
|
|
194
|
-
|
|
200
|
+
if not self.allowed(self.liftperm):
|
|
201
|
+
await self._reqUserAllowed(self.readperm)
|
|
195
202
|
return self.layr.iden
|
|
196
203
|
|
|
197
204
|
BUID_CACHE_SIZE = 10000
|
|
@@ -3350,7 +3357,7 @@ class Layer(s_nexus.Pusher):
|
|
|
3350
3357
|
nodeedits = [(buid, newp_formname, [set_edit])]
|
|
3351
3358
|
|
|
3352
3359
|
_, changes = await self.saveNodeEdits(nodeedits, meta)
|
|
3353
|
-
return
|
|
3360
|
+
return any(c[2] for c in changes)
|
|
3354
3361
|
|
|
3355
3362
|
async def delStorNode(self, buid, meta):
|
|
3356
3363
|
'''
|
|
@@ -3434,7 +3441,7 @@ class Layer(s_nexus.Pusher):
|
|
|
3434
3441
|
if changed: # pragma: no cover
|
|
3435
3442
|
return changed
|
|
3436
3443
|
|
|
3437
|
-
return
|
|
3444
|
+
return any(c[2] for c in changes)
|
|
3438
3445
|
|
|
3439
3446
|
for n2iden, edges in n2edges.items():
|
|
3440
3447
|
edits = [(EDIT_EDGE_DEL, edge, ()) for edge in edges]
|
|
@@ -3455,7 +3462,7 @@ class Layer(s_nexus.Pusher):
|
|
|
3455
3462
|
nodeedits = [(buid, oldp_formname, [del_edit])]
|
|
3456
3463
|
|
|
3457
3464
|
_, changes = await self.saveNodeEdits(nodeedits, meta)
|
|
3458
|
-
return
|
|
3465
|
+
return any(c[2] for c in changes)
|
|
3459
3466
|
|
|
3460
3467
|
async def delNodeData(self, buid, meta, name=None):
|
|
3461
3468
|
'''
|
|
@@ -3480,7 +3487,7 @@ class Layer(s_nexus.Pusher):
|
|
|
3480
3487
|
nodeedits = [(buid, sode.get('form'), edits)]
|
|
3481
3488
|
|
|
3482
3489
|
_, changes = await self.saveNodeEdits(nodeedits, meta)
|
|
3483
|
-
return
|
|
3490
|
+
return any(c[2] for c in changes)
|
|
3484
3491
|
|
|
3485
3492
|
async def delEdge(self, n1buid, verb, n2buid, meta):
|
|
3486
3493
|
sode = self._getStorNode(n1buid)
|
|
@@ -3497,7 +3504,7 @@ class Layer(s_nexus.Pusher):
|
|
|
3497
3504
|
nodeedits = [(n1buid, sode.get('form'), edits)]
|
|
3498
3505
|
|
|
3499
3506
|
_, changes = await self.saveNodeEdits(nodeedits, meta)
|
|
3500
|
-
return
|
|
3507
|
+
return any(c[2] for c in changes)
|
|
3501
3508
|
|
|
3502
3509
|
async def storNodeEdits(self, nodeedits, meta):
|
|
3503
3510
|
|
synapse/lib/nexus.py
CHANGED
|
@@ -572,7 +572,7 @@ class NexsRoot(s_base.Base):
|
|
|
572
572
|
|
|
573
573
|
offs, args = item
|
|
574
574
|
if offs != self.nexslog.index():
|
|
575
|
-
logger.error('Local Nexus offset is out of sync from remote cell! Aborting mirror sync')
|
|
575
|
+
logger.error(f'Local Nexus offset is out of sync from remote cell! Aborting mirror sync. Local offs={self.nexslog.index()}, Remote {offs=}')
|
|
576
576
|
await self.fini()
|
|
577
577
|
return
|
|
578
578
|
|
synapse/lib/parser.py
CHANGED
|
@@ -669,6 +669,7 @@ ruleClassMap = {
|
|
|
669
669
|
'condsetoper': s_ast.CondSetOper,
|
|
670
670
|
'condtrysetoper': lambda astinfo, kids: s_ast.CondSetOper(astinfo, kids, errok=True),
|
|
671
671
|
'condsubq': s_ast.SubqCond,
|
|
672
|
+
'derefprops': s_ast.DerefProps,
|
|
672
673
|
'dollarexpr': s_ast.DollarExpr,
|
|
673
674
|
'edgeaddn1': s_ast.EditEdgeAdd,
|
|
674
675
|
'edgedeln1': s_ast.EditEdgeDel,
|
synapse/lib/rstorm.py
CHANGED
|
@@ -344,6 +344,7 @@ class StormRst(s_base.Base):
|
|
|
344
344
|
'storm-cortex': self._handleStormCortex,
|
|
345
345
|
'storm-envvar': self._handleStormEnvVar,
|
|
346
346
|
'storm-expect': self._handleStormExpect,
|
|
347
|
+
'storm-python-path': self._handlePythonPath,
|
|
347
348
|
'storm-multiline': self._handleStormMultiline,
|
|
348
349
|
'storm-mock-http': self._handleStormMockHttp,
|
|
349
350
|
'storm-vcr-opts': self._handleStormVcrOpts,
|
|
@@ -374,6 +375,22 @@ class StormRst(s_base.Base):
|
|
|
374
375
|
raise s_exc.NoSuchName(mesg=f'The {directive} directive is not supported', directive=directive)
|
|
375
376
|
return handler
|
|
376
377
|
|
|
378
|
+
async def _handlePythonPath(self, text):
|
|
379
|
+
'''
|
|
380
|
+
Add the text to sys.path.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
text: The path to add.
|
|
384
|
+
'''
|
|
385
|
+
if not os.path.isdir(text):
|
|
386
|
+
raise s_exc.NoSuchDir(mesg=f'The path {text} is not a directory', path=text)
|
|
387
|
+
if text not in sys.path:
|
|
388
|
+
logger.debug(f'Inserting {text} into sys.path')
|
|
389
|
+
sys.path.insert(0, text)
|
|
390
|
+
def onfini():
|
|
391
|
+
sys.path.remove(text)
|
|
392
|
+
self.onfini(onfini)
|
|
393
|
+
|
|
377
394
|
async def _handleStorm(self, text):
|
|
378
395
|
'''
|
|
379
396
|
Run a Storm command and generate text from the output.
|
|
@@ -618,7 +635,8 @@ class StormRst(s_base.Base):
|
|
|
618
635
|
query = query.replace('--fail-ok', '')
|
|
619
636
|
query = query.strip()
|
|
620
637
|
|
|
621
|
-
env =
|
|
638
|
+
env = dict(os.environ)
|
|
639
|
+
env.update(self.context.get('shell-env', {}))
|
|
622
640
|
|
|
623
641
|
stderr = None
|
|
624
642
|
if opts.include_stderr:
|
synapse/lib/schemas.py
CHANGED
|
@@ -816,6 +816,10 @@ _reqValidPkgdefSchema = {
|
|
|
816
816
|
'items': {'type': 'array',
|
|
817
817
|
'items': {'type': 'string'}},
|
|
818
818
|
},
|
|
819
|
+
'asroot:ondeny:import': {
|
|
820
|
+
'type': 'string',
|
|
821
|
+
'enum': ['allow', 'warn', 'deny'],
|
|
822
|
+
},
|
|
819
823
|
},
|
|
820
824
|
'additionalProperties': True,
|
|
821
825
|
'required': ['name', 'storm']
|
synapse/lib/snap.py
CHANGED
|
@@ -1305,6 +1305,11 @@ class Snap(s_base.Base):
|
|
|
1305
1305
|
mesg = 'The snapshot is in read-only mode.'
|
|
1306
1306
|
raise s_exc.IsReadOnly(mesg=mesg)
|
|
1307
1307
|
|
|
1308
|
+
useriden = meta.get('user')
|
|
1309
|
+
if useriden is None:
|
|
1310
|
+
mesg = 'meta is missing user key. Cannot process edits.'
|
|
1311
|
+
raise s_exc.BadArg(mesg=mesg, name='user')
|
|
1312
|
+
|
|
1308
1313
|
wlyr = self.wlyr
|
|
1309
1314
|
nodes = []
|
|
1310
1315
|
callbacks = []
|
|
@@ -1344,12 +1349,12 @@ class Snap(s_base.Base):
|
|
|
1344
1349
|
if etyp == s_layer.EDIT_NODE_ADD:
|
|
1345
1350
|
node.bylayer['ndef'] = wlyr.iden
|
|
1346
1351
|
callbacks.append((node.form.wasAdded, (node,)))
|
|
1347
|
-
callbacks.append((self.view.runNodeAdd, (node,)))
|
|
1352
|
+
callbacks.append((self.view.runNodeAdd, (node, useriden)))
|
|
1348
1353
|
continue
|
|
1349
1354
|
|
|
1350
1355
|
if etyp == s_layer.EDIT_NODE_DEL:
|
|
1351
1356
|
callbacks.append((node.form.wasDeleted, (node,)))
|
|
1352
|
-
callbacks.append((self.view.runNodeDel, (node,)))
|
|
1357
|
+
callbacks.append((self.view.runNodeDel, (node, useriden)))
|
|
1353
1358
|
continue
|
|
1354
1359
|
|
|
1355
1360
|
if etyp == s_layer.EDIT_PROP_SET:
|
|
@@ -1365,7 +1370,7 @@ class Snap(s_base.Base):
|
|
|
1365
1370
|
node.bylayer['props'][name] = wlyr.iden
|
|
1366
1371
|
|
|
1367
1372
|
callbacks.append((prop.wasSet, (node, oldv)))
|
|
1368
|
-
callbacks.append((self.view.runPropSet, (node, prop, oldv)))
|
|
1373
|
+
callbacks.append((self.view.runPropSet, (node, prop, oldv, useriden)))
|
|
1369
1374
|
continue
|
|
1370
1375
|
|
|
1371
1376
|
if etyp == s_layer.EDIT_PROP_DEL:
|
|
@@ -1381,7 +1386,7 @@ class Snap(s_base.Base):
|
|
|
1381
1386
|
node.bylayer['props'].pop(name, None)
|
|
1382
1387
|
|
|
1383
1388
|
callbacks.append((prop.wasDel, (node, oldv)))
|
|
1384
|
-
callbacks.append((self.view.runPropSet, (node, prop, oldv)))
|
|
1389
|
+
callbacks.append((self.view.runPropSet, (node, prop, oldv, useriden)))
|
|
1385
1390
|
continue
|
|
1386
1391
|
|
|
1387
1392
|
if etyp == s_layer.EDIT_TAG_SET:
|
|
@@ -1391,7 +1396,7 @@ class Snap(s_base.Base):
|
|
|
1391
1396
|
node.tags[tag] = valu
|
|
1392
1397
|
node.bylayer['tags'][tag] = wlyr.iden
|
|
1393
1398
|
|
|
1394
|
-
callbacks.append((self.view.runTagAdd, (node, tag, valu)))
|
|
1399
|
+
callbacks.append((self.view.runTagAdd, (node, tag, valu, useriden,)))
|
|
1395
1400
|
continue
|
|
1396
1401
|
|
|
1397
1402
|
if etyp == s_layer.EDIT_TAG_DEL:
|
|
@@ -1401,7 +1406,7 @@ class Snap(s_base.Base):
|
|
|
1401
1406
|
node.tags.pop(tag, None)
|
|
1402
1407
|
node.bylayer['tags'].pop(tag, None)
|
|
1403
1408
|
|
|
1404
|
-
callbacks.append((self.view.runTagDel, (node, tag, oldv)))
|
|
1409
|
+
callbacks.append((self.view.runTagDel, (node, tag, oldv, useriden)))
|
|
1405
1410
|
continue
|
|
1406
1411
|
|
|
1407
1412
|
if etyp == s_layer.EDIT_TAGPROP_SET:
|
|
@@ -1436,14 +1441,15 @@ class Snap(s_base.Base):
|
|
|
1436
1441
|
if etyp == s_layer.EDIT_EDGE_ADD:
|
|
1437
1442
|
verb, n2iden = parms
|
|
1438
1443
|
n2 = await self.getNodeByBuid(s_common.uhex(n2iden))
|
|
1439
|
-
callbacks.append((self.view.runEdgeAdd, (node, verb, n2)))
|
|
1444
|
+
callbacks.append((self.view.runEdgeAdd, (node, verb, n2, useriden)))
|
|
1440
1445
|
|
|
1441
1446
|
if etyp == s_layer.EDIT_EDGE_DEL:
|
|
1442
1447
|
verb, n2iden = parms
|
|
1443
1448
|
n2 = await self.getNodeByBuid(s_common.uhex(n2iden))
|
|
1444
|
-
callbacks.append((self.view.runEdgeDel, (node, verb, n2)))
|
|
1449
|
+
callbacks.append((self.view.runEdgeDel, (node, verb, n2, useriden)))
|
|
1445
1450
|
|
|
1446
|
-
|
|
1451
|
+
for func, args in callbacks:
|
|
1452
|
+
await func(*args)
|
|
1447
1453
|
|
|
1448
1454
|
if actualedits:
|
|
1449
1455
|
await self.fire('node:edits', edits=actualedits)
|