synapse 2.164.0__py311-none-any.whl → 2.166.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 +3 -3
- synapse/cmds/cortex.py +1 -6
- synapse/common.py +7 -1
- synapse/cortex.py +145 -192
- synapse/datamodel.py +36 -1
- synapse/lib/agenda.py +87 -97
- synapse/lib/aha.py +51 -0
- synapse/lib/ast.py +22 -23
- synapse/lib/base.py +0 -6
- synapse/lib/boss.py +3 -0
- synapse/lib/cell.py +70 -39
- synapse/lib/certdir.py +9 -0
- synapse/lib/hiveauth.py +65 -12
- synapse/lib/httpapi.py +1 -0
- synapse/lib/modelrev.py +121 -33
- synapse/lib/modules.py +1 -0
- synapse/lib/nexus.py +64 -26
- synapse/lib/parser.py +2 -0
- synapse/lib/schemas.py +14 -0
- synapse/lib/snap.py +50 -4
- synapse/lib/storm.lark +4 -3
- synapse/lib/storm.py +96 -22
- synapse/lib/storm_format.py +1 -0
- synapse/lib/stormlib/aha.py +7 -1
- synapse/lib/stormlib/auth.py +13 -5
- synapse/lib/stormlib/cache.py +202 -0
- synapse/lib/stormlib/cortex.py +147 -8
- synapse/lib/stormlib/gen.py +53 -6
- synapse/lib/stormlib/math.py +1 -1
- synapse/lib/stormlib/model.py +11 -1
- synapse/lib/stormlib/spooled.py +109 -0
- synapse/lib/stormlib/vault.py +1 -1
- synapse/lib/stormtypes.py +113 -17
- synapse/lib/trigger.py +36 -47
- synapse/lib/types.py +29 -2
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +80 -53
- synapse/models/economic.py +174 -5
- synapse/models/files.py +2 -0
- synapse/models/inet.py +77 -2
- synapse/models/infotech.py +12 -12
- synapse/models/orgs.py +72 -21
- synapse/models/person.py +40 -11
- synapse/models/risk.py +78 -24
- synapse/models/science.py +102 -0
- synapse/telepath.py +117 -35
- synapse/tests/test_cortex.py +84 -158
- synapse/tests/test_datamodel.py +22 -0
- synapse/tests/test_lib_agenda.py +52 -96
- synapse/tests/test_lib_aha.py +126 -4
- synapse/tests/test_lib_ast.py +412 -6
- synapse/tests/test_lib_cell.py +24 -8
- synapse/tests/test_lib_certdir.py +32 -0
- synapse/tests/test_lib_grammar.py +9 -1
- synapse/tests/test_lib_httpapi.py +0 -1
- synapse/tests/test_lib_jupyter.py +0 -1
- synapse/tests/test_lib_modelrev.py +41 -0
- synapse/tests/test_lib_nexus.py +38 -0
- synapse/tests/test_lib_storm.py +95 -5
- synapse/tests/test_lib_stormlib_cache.py +272 -0
- synapse/tests/test_lib_stormlib_cortex.py +71 -0
- synapse/tests/test_lib_stormlib_gen.py +37 -2
- synapse/tests/test_lib_stormlib_model.py +2 -0
- synapse/tests/test_lib_stormlib_spooled.py +190 -0
- synapse/tests/test_lib_stormlib_vault.py +12 -3
- synapse/tests/test_lib_stormsvc.py +0 -10
- synapse/tests/test_lib_stormtypes.py +60 -8
- synapse/tests/test_lib_trigger.py +20 -2
- synapse/tests/test_lib_types.py +17 -1
- synapse/tests/test_model_economic.py +114 -0
- synapse/tests/test_model_files.py +2 -0
- synapse/tests/test_model_inet.py +73 -1
- synapse/tests/test_model_infotech.py +2 -2
- synapse/tests/test_model_orgs.py +10 -1
- synapse/tests/test_model_risk.py +30 -2
- synapse/tests/test_model_science.py +59 -0
- synapse/tests/test_model_syn.py +0 -1
- synapse/tests/test_telepath.py +30 -7
- synapse/tests/test_tools_modrole.py +81 -0
- synapse/tests/test_tools_moduser.py +105 -0
- synapse/tools/modrole.py +59 -7
- synapse/tools/moduser.py +78 -10
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/RECORD +87 -83
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +1 -1
- synapse/lib/provenance.py +0 -111
- synapse/tests/test_lib_provenance.py +0 -37
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import synapse.exc as s_exc
|
|
2
|
+
import synapse.lib.msgpack as s_msgpack
|
|
3
|
+
import synapse.lib.spooled as s_spooled
|
|
4
|
+
import synapse.lib.stormtypes as s_stormtypes
|
|
5
|
+
|
|
6
|
+
@s_stormtypes.registry.registerLib
|
|
7
|
+
class LibSpooled(s_stormtypes.Lib):
|
|
8
|
+
'''
|
|
9
|
+
A Storm Library for interacting with Spooled Objects.
|
|
10
|
+
'''
|
|
11
|
+
_storm_locals = (
|
|
12
|
+
{'name': 'set', 'desc': '''
|
|
13
|
+
Get a Spooled Storm Set object.
|
|
14
|
+
|
|
15
|
+
A Spooled Storm Set object is memory-safe to grow to extraordinarily large sizes,
|
|
16
|
+
as it will fallback to file backed storage, with two restrictions. First
|
|
17
|
+
is that all items in the set can be serialized to a file if the set grows too large,
|
|
18
|
+
so all items added must be a serializable Storm primitive. Second is that when an
|
|
19
|
+
item is added to the Set, because it could be immediately written disk,
|
|
20
|
+
do not hold any references to it outside of the Set itself, as the two objects could
|
|
21
|
+
differ.
|
|
22
|
+
''',
|
|
23
|
+
'type': {'type': 'function', '_funcname': '_methSet',
|
|
24
|
+
'args': (
|
|
25
|
+
{'name': '*vals', 'type': 'any', 'desc': 'Initial values to place in the set.', },
|
|
26
|
+
),
|
|
27
|
+
'returns': {'type': 'set', 'desc': 'The new set.'}}},
|
|
28
|
+
)
|
|
29
|
+
_storm_lib_path = ('spooled',)
|
|
30
|
+
|
|
31
|
+
def getObjLocals(self):
|
|
32
|
+
return {
|
|
33
|
+
'set': self._methSet,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
37
|
+
async def _methSet(self, *vals):
|
|
38
|
+
core = self.runt.snap.core
|
|
39
|
+
spool = await s_spooled.Set.anit(dirn=core.dirn, cell=core, size=1000)
|
|
40
|
+
|
|
41
|
+
valu = list(vals)
|
|
42
|
+
for item in valu:
|
|
43
|
+
if s_stormtypes.ismutable(item):
|
|
44
|
+
mesg = f'{await s_stormtypes.torepr(item)} is mutable and cannot be used in a set.'
|
|
45
|
+
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
46
|
+
|
|
47
|
+
if not s_msgpack.isok(item):
|
|
48
|
+
mesg = f'{await s_stormtypes.torepr(item)} is not safe to be used in a SpooledSet.'
|
|
49
|
+
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
50
|
+
|
|
51
|
+
await spool.add(item)
|
|
52
|
+
|
|
53
|
+
return SpooledSet(spool)
|
|
54
|
+
|
|
55
|
+
@s_stormtypes.registry.registerType
|
|
56
|
+
class SpooledSet(s_stormtypes.Set):
|
|
57
|
+
'''
|
|
58
|
+
A StormLib API instance of a Storm Set object that can fallback to lmdb.
|
|
59
|
+
'''
|
|
60
|
+
_storm_typename = 'spooled:set'
|
|
61
|
+
_ismutable = True
|
|
62
|
+
|
|
63
|
+
def __init__(self, valu, path=None):
|
|
64
|
+
|
|
65
|
+
s_stormtypes.Prim.__init__(self, valu, path=path)
|
|
66
|
+
self.locls.update(self.getObjLocals())
|
|
67
|
+
|
|
68
|
+
async def iter(self):
|
|
69
|
+
async for item in self.valu:
|
|
70
|
+
yield item
|
|
71
|
+
|
|
72
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
73
|
+
async def _methSetAdd(self, *items):
|
|
74
|
+
for i in items:
|
|
75
|
+
if s_stormtypes.ismutable(i):
|
|
76
|
+
mesg = f'{await s_stormtypes.torepr(i)} is mutable and cannot be used in a set.'
|
|
77
|
+
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
78
|
+
|
|
79
|
+
if not s_msgpack.isok(i):
|
|
80
|
+
mesg = f'{await s_stormtypes.torepr(i)} is not safe to be used in a SpooledSet.'
|
|
81
|
+
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
82
|
+
|
|
83
|
+
await self.valu.add(i)
|
|
84
|
+
|
|
85
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
86
|
+
async def _methSetAdds(self, *items):
|
|
87
|
+
for item in items:
|
|
88
|
+
async for i in s_stormtypes.toiter(item):
|
|
89
|
+
if s_stormtypes.ismutable(i):
|
|
90
|
+
mesg = f'{await s_stormtypes.torepr(i)} is mutable and cannot be used in a set.'
|
|
91
|
+
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
92
|
+
|
|
93
|
+
if not s_msgpack.isok(i):
|
|
94
|
+
mesg = f'{await s_stormtypes.torepr(i)} is not safe to be used in a SpooledSet.'
|
|
95
|
+
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
96
|
+
|
|
97
|
+
await self.valu.add(i)
|
|
98
|
+
|
|
99
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
100
|
+
async def _methSetList(self):
|
|
101
|
+
return [x async for x in self.valu]
|
|
102
|
+
|
|
103
|
+
async def stormrepr(self):
|
|
104
|
+
reprs = [await s_stormtypes.torepr(k) async for k in self.valu]
|
|
105
|
+
rval = ', '.join(reprs)
|
|
106
|
+
return f'{{{rval}}}'
|
|
107
|
+
|
|
108
|
+
async def value(self):
|
|
109
|
+
return set([x async for x in self.valu])
|
synapse/lib/stormlib/vault.py
CHANGED
synapse/lib/stormtypes.py
CHANGED
|
@@ -36,7 +36,6 @@ import synapse.lib.trigger as s_trigger
|
|
|
36
36
|
import synapse.lib.urlhelp as s_urlhelp
|
|
37
37
|
import synapse.lib.version as s_version
|
|
38
38
|
import synapse.lib.stormctrl as s_stormctrl
|
|
39
|
-
import synapse.lib.provenance as s_provenance
|
|
40
39
|
|
|
41
40
|
logger = logging.getLogger(__name__)
|
|
42
41
|
|
|
@@ -907,6 +906,18 @@ class LibService(Lib):
|
|
|
907
906
|
'returns': {'type': 'boolean', 'desc': 'Returns true if the service is available, false on a '
|
|
908
907
|
'timeout waiting for the service to be ready.', }}},
|
|
909
908
|
)
|
|
909
|
+
_storm_lib_perms = (
|
|
910
|
+
{'perm': ('service', 'add'), 'gate': 'cortex',
|
|
911
|
+
'desc': 'Controls the ability to add a Storm Service to the Cortex.'},
|
|
912
|
+
{'perm': ('service', 'del'), 'gate': 'cortex',
|
|
913
|
+
'desc': 'Controls the ability to delete a Storm Service from the Cortex'},
|
|
914
|
+
{'perm': ('service', 'get'), 'gate': 'cortex',
|
|
915
|
+
'desc': 'Controls the ability to get the Service object for any Storm Service.'},
|
|
916
|
+
{'perm': ('service', 'get', '<iden>'), 'gate': 'cortex',
|
|
917
|
+
'desc': 'Controls the ability to get the Service object for a Storm Service by iden.'},
|
|
918
|
+
{'perm': ('service', 'list'), 'gate': 'cortex',
|
|
919
|
+
'desc': 'Controls the ability to list all available Storm Services and their service definitions.'},
|
|
920
|
+
)
|
|
910
921
|
_storm_lib_path = ('service',)
|
|
911
922
|
|
|
912
923
|
def getObjLocals(self):
|
|
@@ -931,6 +942,7 @@ class LibService(Lib):
|
|
|
931
942
|
except s_exc.AuthDeny:
|
|
932
943
|
raise e from None
|
|
933
944
|
else:
|
|
945
|
+
# TODO: Remove support for this permission in 3.0.0
|
|
934
946
|
mesg = 'Use of service.get.<servicename> permissions are deprecated.'
|
|
935
947
|
await self.runt.warnonce(mesg, svcname=ssvc.name, svciden=ssvc.iden)
|
|
936
948
|
|
|
@@ -3192,6 +3204,26 @@ class LibRegx(Lib):
|
|
|
3192
3204
|
'default': 0, },
|
|
3193
3205
|
),
|
|
3194
3206
|
'returns': {'type': 'str', 'desc': 'The new string with matches replaced.', }}},
|
|
3207
|
+
{'name': 'escape', 'desc': '''
|
|
3208
|
+
Escape arbitrary strings for use in a regular expression pattern.
|
|
3209
|
+
|
|
3210
|
+
Example:
|
|
3211
|
+
|
|
3212
|
+
Escape node values for use in a regex pattern::
|
|
3213
|
+
|
|
3214
|
+
for $match in $lib.regex.findall($lib.regex.escape($node.repr()), $mydocument) {
|
|
3215
|
+
// do something with $match
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
Escape node values for use in regular expression filters::
|
|
3219
|
+
|
|
3220
|
+
it:dev:str~=$lib.regex.escape($node.repr())
|
|
3221
|
+
''',
|
|
3222
|
+
'type': {'type': 'function', '_funcname': 'escape',
|
|
3223
|
+
'args': (
|
|
3224
|
+
{'name': 'text', 'type': 'str', 'desc': 'The text to escape.', },
|
|
3225
|
+
),
|
|
3226
|
+
'returns': {'type': 'str', 'desc': 'Input string with special characters escaped.', }}},
|
|
3195
3227
|
{'name': 'flags.i', 'desc': 'Regex flag to indicate that case insensitive matches are allowed.',
|
|
3196
3228
|
'type': 'int', },
|
|
3197
3229
|
{'name': 'flags.m', 'desc': 'Regex flag to indicate that multiline matches are allowed.', 'type': 'int', },
|
|
@@ -3208,6 +3240,7 @@ class LibRegx(Lib):
|
|
|
3208
3240
|
'matches': self.matches,
|
|
3209
3241
|
'findall': self.findall,
|
|
3210
3242
|
'replace': self.replace,
|
|
3243
|
+
'escape': self.escape,
|
|
3211
3244
|
'flags': {'i': regex.IGNORECASE,
|
|
3212
3245
|
'm': regex.MULTILINE,
|
|
3213
3246
|
},
|
|
@@ -3258,6 +3291,11 @@ class LibRegx(Lib):
|
|
|
3258
3291
|
regx = await self._getRegx(pattern, flags)
|
|
3259
3292
|
return regx.findall(text)
|
|
3260
3293
|
|
|
3294
|
+
@stormfunc(readonly=True)
|
|
3295
|
+
async def escape(self, text):
|
|
3296
|
+
text = await tostr(text)
|
|
3297
|
+
return regex.escape(text)
|
|
3298
|
+
|
|
3261
3299
|
@registry.registerLib
|
|
3262
3300
|
class LibCsv(Lib):
|
|
3263
3301
|
'''
|
|
@@ -3399,13 +3437,14 @@ class LibFeed(Lib):
|
|
|
3399
3437
|
data = await toprim(data)
|
|
3400
3438
|
|
|
3401
3439
|
self.runt.layerConfirm(('feed:data', *name.split('.')))
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3440
|
+
|
|
3441
|
+
# small work around for the feed API consistency
|
|
3442
|
+
if name == 'syn.nodes':
|
|
3443
|
+
async for node in self.runt.snap.addNodes(data):
|
|
3444
|
+
yield node
|
|
3445
|
+
return
|
|
3446
|
+
|
|
3447
|
+
await self.runt.snap.addFeedData(name, data)
|
|
3409
3448
|
|
|
3410
3449
|
@stormfunc(readonly=True)
|
|
3411
3450
|
async def _libList(self):
|
|
@@ -3417,11 +3456,12 @@ class LibFeed(Lib):
|
|
|
3417
3456
|
data = await toprim(data)
|
|
3418
3457
|
|
|
3419
3458
|
self.runt.layerConfirm(('feed:data', *name.split('.')))
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3459
|
+
|
|
3460
|
+
# TODO this should be a reentrent safe with block
|
|
3461
|
+
strict = self.runt.snap.strict
|
|
3462
|
+
self.runt.snap.strict = False
|
|
3463
|
+
await self.runt.snap.addFeedData(name, data)
|
|
3464
|
+
self.runt.snap.strict = strict
|
|
3425
3465
|
|
|
3426
3466
|
@registry.registerLib
|
|
3427
3467
|
class LibPipe(Lib):
|
|
@@ -6047,6 +6087,8 @@ class Node(Prim):
|
|
|
6047
6087
|
'desc': 'An optional prefix to match tags under.', },
|
|
6048
6088
|
{'name': 'apply', 'type': 'boolean', 'desc': 'If true, apply the diff.',
|
|
6049
6089
|
'default': False, },
|
|
6090
|
+
{'name': 'norm', 'type': 'boolean', 'default': False,
|
|
6091
|
+
'desc': 'Optionally norm the list of tags. If a prefix is provided, it will not be normed.'},
|
|
6050
6092
|
),
|
|
6051
6093
|
'returns':
|
|
6052
6094
|
{'type': 'dict',
|
|
@@ -6198,8 +6240,23 @@ class Node(Prim):
|
|
|
6198
6240
|
ret.append(groups)
|
|
6199
6241
|
return ret
|
|
6200
6242
|
|
|
6201
|
-
async def _methNodeDiffTags(self, tags, prefix=None, apply=False):
|
|
6202
|
-
|
|
6243
|
+
async def _methNodeDiffTags(self, tags, prefix=None, apply=False, norm=False):
|
|
6244
|
+
norm = await tobool(norm)
|
|
6245
|
+
apply = await tobool(apply)
|
|
6246
|
+
|
|
6247
|
+
if norm:
|
|
6248
|
+
normtags = set()
|
|
6249
|
+
tagpart = self.valu.snap.core.model.type('syn:tag:part')
|
|
6250
|
+
|
|
6251
|
+
async for part in toiter(tags):
|
|
6252
|
+
try:
|
|
6253
|
+
normtags.add(tagpart.norm(part)[0])
|
|
6254
|
+
except s_exc.BadTypeValu:
|
|
6255
|
+
pass
|
|
6256
|
+
|
|
6257
|
+
tags = normtags
|
|
6258
|
+
else:
|
|
6259
|
+
tags = set(await toprim(tags))
|
|
6203
6260
|
|
|
6204
6261
|
if prefix:
|
|
6205
6262
|
prefix = tuple((await tostr(prefix)).split('.'))
|
|
@@ -7443,7 +7500,7 @@ class View(Prim):
|
|
|
7443
7500
|
|
|
7444
7501
|
{'name': 'getPropArrayCount',
|
|
7445
7502
|
'desc': '''
|
|
7446
|
-
Get the number of
|
|
7503
|
+
Get the number of individual array property values in the View for the given array property name.
|
|
7447
7504
|
|
|
7448
7505
|
Notes:
|
|
7449
7506
|
This is a fast approximate count calculated by summing the number of
|
|
@@ -7537,6 +7594,18 @@ class View(Prim):
|
|
|
7537
7594
|
'args': (),
|
|
7538
7595
|
'returns': {'name': 'Yields', 'type': 'dict',
|
|
7539
7596
|
'desc': 'Yields previously successful merges into the view.'}}},
|
|
7597
|
+
{'name': 'getMergingViews', 'desc': 'Get a list of idens of Views that have open merge requests to this View.',
|
|
7598
|
+
'type': {'type': 'function', '_funcname': 'getMergingViews',
|
|
7599
|
+
'args': (),
|
|
7600
|
+
'returns': {'name': 'idens', 'type': 'list', 'desc': 'The list of View idens that have an open merge request into this View.'}}},
|
|
7601
|
+
{'name': 'setMergeVoteComment', 'desc': 'Set the comment associated with your vote on a merge request.',
|
|
7602
|
+
'type': {'type': 'function', '_funcname': 'setMergeVoteComment',
|
|
7603
|
+
'args': ({'name': 'comment', 'type': 'str', 'desc': 'The text comment to set for the merge vote'},),
|
|
7604
|
+
'returns': {'type': 'dict', 'desc': 'The fully updated vote record.'}}},
|
|
7605
|
+
{'name': 'setMergeComment', 'desc': 'Set the main comment/description of a merge request.',
|
|
7606
|
+
'type': {'type': 'function', '_funcname': 'setMergeComment',
|
|
7607
|
+
'args': ({'name': 'comment', 'type': 'str', 'desc': 'The text comment to set for the merge request'}, ),
|
|
7608
|
+
'returns': {'type': 'dict', 'desc': 'The updated merge request.'}}},
|
|
7540
7609
|
)
|
|
7541
7610
|
_storm_typename = 'view'
|
|
7542
7611
|
_ismutable = False
|
|
@@ -7577,10 +7646,13 @@ class View(Prim):
|
|
|
7577
7646
|
'getMerges': self.getMerges,
|
|
7578
7647
|
'delMergeVote': self.delMergeVote,
|
|
7579
7648
|
'setMergeVote': self.setMergeVote,
|
|
7649
|
+
'setMergeVoteComment': self.setMergeVoteComment,
|
|
7580
7650
|
'getMergeRequest': self.getMergeRequest,
|
|
7581
7651
|
'getMergeRequestSummary': self.getMergeRequestSummary,
|
|
7582
7652
|
'delMergeRequest': self.delMergeRequest,
|
|
7583
7653
|
'setMergeRequest': self.setMergeRequest,
|
|
7654
|
+
'setMergeComment': self.setMergeComment,
|
|
7655
|
+
'getMergingViews': self.getMergingViews,
|
|
7584
7656
|
}
|
|
7585
7657
|
|
|
7586
7658
|
async def addNode(self, form, valu, props=None):
|
|
@@ -7888,6 +7960,22 @@ class View(Prim):
|
|
|
7888
7960
|
|
|
7889
7961
|
return await view.setMergeRequest(mreq)
|
|
7890
7962
|
|
|
7963
|
+
async def setMergeComment(self, comment):
|
|
7964
|
+
view = self._reqView()
|
|
7965
|
+
quorum = view.reqParentQuorum()
|
|
7966
|
+
|
|
7967
|
+
if not self.runt.isAdmin(gateiden=view.iden):
|
|
7968
|
+
mesg = 'Editing a merge request requires admin permissions on the view.'
|
|
7969
|
+
raise s_exc.AuthDeny(mesg=mesg)
|
|
7970
|
+
|
|
7971
|
+
return await view.setMergeComment((await tostr(comment)))
|
|
7972
|
+
|
|
7973
|
+
async def getMergingViews(self):
|
|
7974
|
+
view = self._reqView()
|
|
7975
|
+
self.runt.confirm(('view', 'read'), gateiden=view.iden)
|
|
7976
|
+
|
|
7977
|
+
return await view.getMergingViews()
|
|
7978
|
+
|
|
7891
7979
|
async def setMergeVote(self, approved=True, comment=None):
|
|
7892
7980
|
view = self._reqView()
|
|
7893
7981
|
quorum = view.reqParentQuorum()
|
|
@@ -7908,6 +7996,11 @@ class View(Prim):
|
|
|
7908
7996
|
|
|
7909
7997
|
return await view.setMergeVote(vote)
|
|
7910
7998
|
|
|
7999
|
+
async def setMergeVoteComment(self, comment):
|
|
8000
|
+
view = self._reqView()
|
|
8001
|
+
|
|
8002
|
+
return await view.setMergeVoteComment(self.runt.user.iden, (await tostr(comment)))
|
|
8003
|
+
|
|
7911
8004
|
async def delMergeVote(self, useriden=None):
|
|
7912
8005
|
view = self._reqView()
|
|
7913
8006
|
quorum = view.reqParentQuorum()
|
|
@@ -8596,7 +8689,7 @@ class LibCron(Lib):
|
|
|
8596
8689
|
'returns': {'type': 'str', 'desc': 'The iden of the CronJob which was moved.'}}},
|
|
8597
8690
|
{'name': 'list', 'desc': 'List CronJobs in the Cortex.',
|
|
8598
8691
|
'type': {'type': 'function', '_funcname': '_methCronList',
|
|
8599
|
-
'returns': {'type': 'list', 'desc': 'A list of ``cronjob`` objects
|
|
8692
|
+
'returns': {'type': 'list', 'desc': 'A list of ``cronjob`` objects.', }}},
|
|
8600
8693
|
{'name': 'enable', 'desc': 'Enable a CronJob in the Cortex.',
|
|
8601
8694
|
'type': {'type': 'function', '_funcname': '_methCronEnable',
|
|
8602
8695
|
'args': (
|
|
@@ -8787,6 +8880,7 @@ class LibCron(Lib):
|
|
|
8787
8880
|
incunit = None
|
|
8788
8881
|
incval = None
|
|
8789
8882
|
reqdict = {}
|
|
8883
|
+
pool = await tobool(kwargs.get('pool', False))
|
|
8790
8884
|
valinfo = { # unit: (minval, next largest unit)
|
|
8791
8885
|
'month': (1, 'year'),
|
|
8792
8886
|
'dayofmonth': (1, 'month'),
|
|
@@ -8892,6 +8986,7 @@ class LibCron(Lib):
|
|
|
8892
8986
|
|
|
8893
8987
|
cdef = {'storm': query,
|
|
8894
8988
|
'reqs': reqdict,
|
|
8989
|
+
'pool': pool,
|
|
8895
8990
|
'incunit': incunit,
|
|
8896
8991
|
'incvals': incval,
|
|
8897
8992
|
'creator': self.runt.user.iden
|
|
@@ -9140,6 +9235,7 @@ class CronJob(Prim):
|
|
|
9140
9235
|
'view': view,
|
|
9141
9236
|
'viewshort': view[:8] + '..',
|
|
9142
9237
|
'query': self.valu.get('query') or '<missing>',
|
|
9238
|
+
'pool': self.valu.get('pool', False),
|
|
9143
9239
|
'isrecur': 'Y' if self.valu.get('recur') else 'N',
|
|
9144
9240
|
'isrunning': 'Y' if self.valu.get('isrunning') else 'N',
|
|
9145
9241
|
'enabled': 'Y' if self.valu.get('enabled', True) else 'N',
|
synapse/lib/trigger.py
CHANGED
|
@@ -11,7 +11,6 @@ import synapse.lib.chop as s_chop
|
|
|
11
11
|
import synapse.lib.cache as s_cache
|
|
12
12
|
import synapse.lib.config as s_config
|
|
13
13
|
import synapse.lib.grammar as s_grammar
|
|
14
|
-
import synapse.lib.provenance as s_provenance
|
|
15
14
|
|
|
16
15
|
logger = logging.getLogger(__name__)
|
|
17
16
|
|
|
@@ -137,49 +136,47 @@ class Triggers:
|
|
|
137
136
|
finally:
|
|
138
137
|
RecursionDepth.reset(token)
|
|
139
138
|
|
|
140
|
-
async def runNodeAdd(self, node
|
|
139
|
+
async def runNodeAdd(self, node):
|
|
141
140
|
with self._recursion_check():
|
|
142
|
-
[await trig.execute(node
|
|
141
|
+
[await trig.execute(node) for trig in self.nodeadd.get(node.form.name, ())]
|
|
143
142
|
|
|
144
|
-
async def runNodeDel(self, node
|
|
143
|
+
async def runNodeDel(self, node):
|
|
145
144
|
with self._recursion_check():
|
|
146
|
-
[await trig.execute(node
|
|
145
|
+
[await trig.execute(node) for trig in self.nodedel.get(node.form.name, ())]
|
|
147
146
|
|
|
148
|
-
async def runPropSet(self, node, prop, oldv
|
|
147
|
+
async def runPropSet(self, node, prop, oldv):
|
|
149
148
|
vars = {'propname': prop.name, 'propfull': prop.full,
|
|
150
149
|
'auto': {'opts': {'propname': prop.name, 'propfull': prop.full, }},
|
|
151
150
|
}
|
|
152
151
|
with self._recursion_check():
|
|
153
|
-
[await trig.execute(node, vars=vars
|
|
152
|
+
[await trig.execute(node, vars=vars) for trig in self.propset.get(prop.full, ())]
|
|
154
153
|
if prop.univ is not None:
|
|
155
|
-
[await trig.execute(node, vars=vars
|
|
154
|
+
[await trig.execute(node, vars=vars) for trig in self.propset.get(prop.univ.full, ())]
|
|
156
155
|
|
|
157
|
-
async def runTagAdd(self, node, tag
|
|
156
|
+
async def runTagAdd(self, node, tag):
|
|
158
157
|
|
|
159
|
-
vars = {'tag': tag,
|
|
160
|
-
'auto': {'opts': {'tag': tag}},
|
|
161
|
-
}
|
|
158
|
+
vars = {'tag': tag, 'auto': {'opts': {'tag': tag}}}
|
|
162
159
|
with self._recursion_check():
|
|
163
160
|
|
|
164
161
|
for trig in self.tagadd.get((node.form.name, tag), ()):
|
|
165
|
-
await trig.execute(node, vars=vars
|
|
162
|
+
await trig.execute(node, vars=vars)
|
|
166
163
|
|
|
167
164
|
for trig in self.tagadd.get((None, tag), ()):
|
|
168
|
-
await trig.execute(node, vars=vars
|
|
165
|
+
await trig.execute(node, vars=vars)
|
|
169
166
|
|
|
170
167
|
# check for form specific globs
|
|
171
168
|
globs = self.tagaddglobs.get(node.form.name)
|
|
172
169
|
if globs is not None:
|
|
173
170
|
for _, trig in globs.get(tag):
|
|
174
|
-
await trig.execute(node, vars=vars
|
|
171
|
+
await trig.execute(node, vars=vars)
|
|
175
172
|
|
|
176
173
|
# check for form agnostic globs
|
|
177
174
|
globs = self.tagaddglobs.get(None)
|
|
178
175
|
if globs is not None:
|
|
179
176
|
for _, trig in globs.get(tag):
|
|
180
|
-
await trig.execute(node, vars=vars
|
|
177
|
+
await trig.execute(node, vars=vars)
|
|
181
178
|
|
|
182
|
-
async def runTagDel(self, node, tag
|
|
179
|
+
async def runTagDel(self, node, tag):
|
|
183
180
|
|
|
184
181
|
vars = {'tag': tag,
|
|
185
182
|
'auto': {'opts': {'tag': tag}},
|
|
@@ -187,24 +184,24 @@ class Triggers:
|
|
|
187
184
|
with self._recursion_check():
|
|
188
185
|
|
|
189
186
|
for trig in self.tagdel.get((node.form.name, tag), ()):
|
|
190
|
-
await trig.execute(node, vars=vars
|
|
187
|
+
await trig.execute(node, vars=vars)
|
|
191
188
|
|
|
192
189
|
for trig in self.tagdel.get((None, tag), ()):
|
|
193
|
-
await trig.execute(node, vars=vars
|
|
190
|
+
await trig.execute(node, vars=vars)
|
|
194
191
|
|
|
195
192
|
# check for form specific globs
|
|
196
193
|
globs = self.tagdelglobs.get(node.form.name)
|
|
197
194
|
if globs is not None:
|
|
198
195
|
for _, trig in globs.get(tag):
|
|
199
|
-
await trig.execute(node, vars=vars
|
|
196
|
+
await trig.execute(node, vars=vars)
|
|
200
197
|
|
|
201
198
|
# check for form agnostic globs
|
|
202
199
|
globs = self.tagdelglobs.get(None)
|
|
203
200
|
if globs is not None:
|
|
204
201
|
for _, trig in globs.get(tag):
|
|
205
|
-
await trig.execute(node, vars=vars
|
|
202
|
+
await trig.execute(node, vars=vars)
|
|
206
203
|
|
|
207
|
-
async def runEdgeAdd(self, n1, verb, n2
|
|
204
|
+
async def runEdgeAdd(self, n1, verb, n2):
|
|
208
205
|
n1form = n1.form.name if n1 else None
|
|
209
206
|
n2form = n2.form.name if n2 else None
|
|
210
207
|
n2iden = n2.iden() if n2 else None
|
|
@@ -252,9 +249,9 @@ class Triggers:
|
|
|
252
249
|
self.edgeaddcache[cachekey] = cached
|
|
253
250
|
|
|
254
251
|
for trig in cached:
|
|
255
|
-
await trig.execute(n1, vars=varz
|
|
252
|
+
await trig.execute(n1, vars=varz)
|
|
256
253
|
|
|
257
|
-
async def runEdgeDel(self, n1, verb, n2
|
|
254
|
+
async def runEdgeDel(self, n1, verb, n2):
|
|
258
255
|
n1form = n1.form.name if n1 else None
|
|
259
256
|
n2form = n2.form.name if n2 else None
|
|
260
257
|
n2iden = n2.iden() if n2 else None
|
|
@@ -302,7 +299,7 @@ class Triggers:
|
|
|
302
299
|
self.edgedelcache[cachekey] = cached
|
|
303
300
|
|
|
304
301
|
for trig in cached:
|
|
305
|
-
await trig.execute(n1, vars=varz
|
|
302
|
+
await trig.execute(n1, vars=varz)
|
|
306
303
|
|
|
307
304
|
async def load(self, tdef):
|
|
308
305
|
|
|
@@ -502,7 +499,7 @@ class Trigger:
|
|
|
502
499
|
def get(self, name):
|
|
503
500
|
return self.tdef.get(name)
|
|
504
501
|
|
|
505
|
-
async def execute(self, node, vars=None
|
|
502
|
+
async def execute(self, node, vars=None):
|
|
506
503
|
'''
|
|
507
504
|
Actually execute the query
|
|
508
505
|
'''
|
|
@@ -514,9 +511,9 @@ class Trigger:
|
|
|
514
511
|
await self.view.addTrigQueue(triginfo)
|
|
515
512
|
return
|
|
516
513
|
|
|
517
|
-
return await self._execute(node, vars=vars
|
|
514
|
+
return await self._execute(node, vars=vars)
|
|
518
515
|
|
|
519
|
-
async def _execute(self, node, vars=None
|
|
516
|
+
async def _execute(self, node, vars=None):
|
|
520
517
|
|
|
521
518
|
locked = self.user.info.get('locked')
|
|
522
519
|
if locked:
|
|
@@ -533,9 +530,6 @@ class Trigger:
|
|
|
533
530
|
|
|
534
531
|
query = await self.view.core.getStormQuery(storm)
|
|
535
532
|
|
|
536
|
-
if view is None:
|
|
537
|
-
view = self.view.iden
|
|
538
|
-
|
|
539
533
|
if vars is None:
|
|
540
534
|
vars = {}
|
|
541
535
|
else:
|
|
@@ -547,28 +541,23 @@ class Trigger:
|
|
|
547
541
|
optvars['form'] = node.ndef[0]
|
|
548
542
|
optvars['valu'] = node.ndef[1]
|
|
549
543
|
|
|
550
|
-
opts = {
|
|
551
|
-
'vars': vars,
|
|
552
|
-
'view': view,
|
|
553
|
-
'user': self.user.iden,
|
|
554
|
-
}
|
|
544
|
+
opts = {'vars': vars, 'user': self.user.iden, 'view': self.view.iden}
|
|
555
545
|
|
|
556
546
|
self.startcount += 1
|
|
557
547
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
async with self.view.core.getStormRuntime(query, opts=opts) as runt:
|
|
548
|
+
try:
|
|
549
|
+
async with self.view.core.getStormRuntime(query, opts=opts) as runt:
|
|
561
550
|
|
|
562
|
-
|
|
563
|
-
|
|
551
|
+
runt.addInput(node)
|
|
552
|
+
await s_common.aspin(runt.execute())
|
|
564
553
|
|
|
565
|
-
|
|
566
|
-
|
|
554
|
+
except (asyncio.CancelledError, s_exc.RecursionLimitHit):
|
|
555
|
+
raise
|
|
567
556
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
557
|
+
except Exception as e:
|
|
558
|
+
self.errcount += 1
|
|
559
|
+
self.lasterrs.append(str(e))
|
|
560
|
+
logger.exception('Trigger encountered exception running storm query %s', storm)
|
|
572
561
|
|
|
573
562
|
def pack(self):
|
|
574
563
|
tdef = self.tdef.copy()
|