From 5f426457ae3ba3edffb6f86114e84db810d7b7f4 Mon Sep 17 00:00:00 2001 From: mikemoritz <57907149+mikemoritz@users.noreply.github.com> Date: Wed, 12 Jun 2024 07:48:56 -0700 Subject: [PATCH 1/3] Add risk:hasvuln migration to risk:vulnerable hotfix (SYN-7120) (#3745) * Also add support for multiline hotfix descriptions --- synapse/lib/stormlib/cell.py | 46 +++++++++++++++++++++--- synapse/lib/stormlib/model.py | 2 +- synapse/tests/test_lib_stormlib_cell.py | 47 +++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/synapse/lib/stormlib/cell.py b/synapse/lib/stormlib/cell.py index fd3f8ebd61e..5e450ab04c6 100644 --- a/synapse/lib/stormlib/cell.py +++ b/synapse/lib/stormlib/cell.py @@ -2,11 +2,16 @@ import logging import synapse.exc as s_exc -import synapse.lib.const as s_const +import synapse.lib.autodoc as s_autodoc import synapse.lib.stormtypes as s_stormtypes logger = logging.getLogger(__name__) +def prepHotfixDesc(txt): + lines = txt.split('\n') + lines = s_autodoc.scrubLines(lines) + lines = s_autodoc.ljuster(lines) + return lines storm_missing_autoadds = ''' $absoluteOrder = $lib.view.list(deporder=$lib.true) @@ -64,6 +69,17 @@ } ''' +storm_migrate_riskhasvuln = ''' +for $view in $lib.view.list(deporder=$lib.true) { + view.exec $view.iden { + $layer = $lib.layer.get() + for ($buid, $sode) in $layer.getStorNodesByForm(risk:hasvuln) { + yield $buid + $lib.model.migration.s.riskHasVulnToVulnerable($node) + } + } +} +''' hotfixes = ( ((1, 0, 0), { @@ -78,6 +94,20 @@ 'desc': 'Populate it:sec:cpe:v2_2 properties from existing CPE where the property is not set.', 'query': storm_missing_cpe22, }), + ((4, 0, 0), { + 'desc': ''' + Create risk:vulnerable nodes from existing risk:hasvuln nodes. + + This hotfix should only be applied after all logic that would create + risk:hasvuln nodes has been updated. The hotfix uses the + $lib.model.migration.s.riskHasVulnToVulnerable() function, + which can be used directly for testing. + + Tags, tag properties, edges, and node data will all be copied + to the risk:vulnerable nodes. + ''', + 'query': storm_migrate_riskhasvuln, + }), ) runtime_fixes_key = 'cortex:runtime:stormfixes' @@ -174,7 +204,9 @@ async def _hotFixesApply(self): assert desc is not None assert vars is not None - await self.runt.printf(f'Applying hotfix {vers} for [{desc}]') + title = prepHotfixDesc(desc)[0] + await self.runt.printf(f'Applying hotfix {vers} for [{title}]') + try: query = await self.runt.getStormQuery(text) async with self.runt.getSubRuntime(query, opts={'vars': vars}) as runt: @@ -206,8 +238,14 @@ async def _hotFixesCheck(self): continue dowork = True - desc = info.get('desc') - await self.runt.printf(f'Would apply fix {vers} for [{desc}]') + + desclines = prepHotfixDesc(info.get('desc')) + await self.runt.printf(f'Would apply fix {vers} for [{desclines[0]}]') + if len(desclines) > 1: + for line in desclines[1:]: + await self.runt.printf(f' {line}' if line else '') + else: + await self.runt.printf('') return dowork diff --git a/synapse/lib/stormlib/model.py b/synapse/lib/stormlib/model.py index cd37a861e2d..0eab3b9047c 100644 --- a/synapse/lib/stormlib/model.py +++ b/synapse/lib/stormlib/model.py @@ -1090,7 +1090,7 @@ async def _riskHasVulnToVulnerable(self, n, nodata=False): self.runt.confirmPropSet(riskvuln.props['vuln']) self.runt.confirmPropSet(riskvuln.props['node']) - if (seen := n.get('.seen')): + if seen := n.get('.seen'): self.runt.confirmPropSet(riskvuln.props['.seen']) props['.seen'] = seen diff --git a/synapse/tests/test_lib_stormlib_cell.py b/synapse/tests/test_lib_stormlib_cell.py index ee91ad37726..0ce45cb1d3e 100644 --- a/synapse/tests/test_lib_stormlib_cell.py +++ b/synapse/tests/test_lib_stormlib_cell.py @@ -312,3 +312,50 @@ async def test_stormfix_cpe2_2(self): self.len(1, await core.nodes('it:sec:cpe:v2_2', opts={'view': view0})) self.len(2, await core.nodes('it:sec:cpe:v2_2', opts={'view': view1})) self.len(1, await core.nodes('it:sec:cpe:v2_2', opts={'view': view2})) + + async def test_stormfix_riskhasvuln(self): + + async with self.getTestCore() as core: + + view0 = core.getView().iden + view1 = await core.callStorm('return($lib.view.get().fork().iden)') + view2 = await core.callStorm('return($lib.view.add(($lib.layer.add().iden,)).iden)') + + self.len(1, await core.nodes(''' + [ risk:hasvuln=* + :vuln={[ risk:vuln=* ]} + :software={[ it:prod:softver=* :name=view0 ]} + ] + ''', opts={'view': view0})) + + self.len(1, await core.nodes(''' + risk:hasvuln + [ :software={[ it:prod:softver=* :name=view1 ]} ] + ''', opts={'view': view1})) + + self.len(1, await core.nodes(''' + [ risk:hasvuln=* + :vuln={[ risk:vuln=* ]} + :host={[ it:host=* :name=view2 ]} + ] + ''', opts={'view': view2})) + + opts = {'vars': {'key': s_stormlib_cell.runtime_fixes_key, 'valu': (2, 0, 0)}} + await core.callStorm('$lib.globals.set($key, $valu)', opts) + + msgs = await core.stormlist('$lib.cell.hotFixesCheck()') + printmesgs = [m[1]['mesg'] for m in msgs if m[0] == 'print'] + self.isin('Would apply fix (3, 0, 0)', printmesgs[0]) + self.eq('', printmesgs[1]) + self.isin('Would apply fix (4, 0, 0)', printmesgs[2]) + self.eq('', printmesgs[3]) + self.isin('This hotfix should', printmesgs[4]) + self.eq('', printmesgs[-1]) + + msgs = await core.stormlist('$lib.cell.hotFixesApply()') + self.stormIsInPrint('Applying hotfix (4, 0, 0) for [Create risk:vulnerable nodes', msgs) + self.stormIsInPrint('Applied hotfix (4, 0, 0)', msgs) + + self.len(1, await core.nodes('risk:vulnerable -> it:prod:softver +:name=view0', opts={'view': view0})) + self.len(1, await core.nodes('risk:vulnerable -> it:prod:softver +:name=view1', opts={'view': view1})) + self.len(1, await core.nodes('risk:vulnerable -> it:host', opts={'view': view2})) From 6f18bfde06f37358cdc2bc79c97d007713abb52e Mon Sep 17 00:00:00 2001 From: James Gross <45212823+rakuy0@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:19:16 -0400 Subject: [PATCH 2/3] Loosen the inet:web:hashtag regex a bit, resolves SYN-7452 (#3751) --- synapse/models/inet.py | 2 +- synapse/tests/test_model_inet.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/synapse/models/inet.py b/synapse/models/inet.py index 96bffab54b1..efd97991ade 100644 --- a/synapse/models/inet.py +++ b/synapse/models/inet.py @@ -1415,7 +1415,7 @@ def getModelDefs(self): 'doc': 'A channel within a web service or instance such as slack or discord.' }), - ('inet:web:hashtag', ('str', {'lower': True, 'regex': r'^#[\w]+$'}), { + ('inet:web:hashtag', ('str', {'lower': True, 'regex': r'^#\w[\w·]*(? Date: Fri, 14 Jun 2024 13:48:33 -0400 Subject: [PATCH 3/3] SYN-7128: view.mergeAllowed/wipeAllowed to pull required perms from index data (#3750) feat: Update layer permissions checking with the user object for optimized checking. bugfix: Update `synapse.lib.coro.pause()` default value for number of iterations from 1000 to 10. --- synapse/cortex.py | 77 +++++++++++++++ synapse/lib/coro.py | 2 +- synapse/lib/layer.py | 169 +++++++++++++++++++------------- synapse/lib/storm.py | 78 ++------------- synapse/lib/view.py | 9 +- synapse/tests/test_lib_layer.py | 55 +---------- synapse/tests/test_lib_view.py | 2 +- 7 files changed, 191 insertions(+), 201 deletions(-) diff --git a/synapse/cortex.py b/synapse/cortex.py index ef421201da4..36c2bdf1eef 100644 --- a/synapse/cortex.py +++ b/synapse/cortex.py @@ -6912,6 +6912,83 @@ async def delVault(self, iden): self.slab.delete(name.encode(), db=self.vaultsbynamedb) self.slab.delete(bidn, db=self.vaultsdb) + def _propAllowedReason(self, user, perms, gateiden=None, default=None): + ''' + Similar to allowed, but always prefer the default value specified by the caller. + Default values are still pulled from permdefs if there is a match there; but still prefer caller default. + This results in a ternary response that can be used to know if a rule had a positive/negative or no match. + The matching reason metadata is also returned. + ''' + if default is None: + permdef = self.getPermDef(perms) + if permdef: + default = permdef.get('default', default) + + return user.getAllowedReason(perms, gateiden=gateiden, default=default) + + def confirmPropSet(self, user, prop, layriden): + meta0 = self._propAllowedReason(user, prop.setperms[0], gateiden=layriden) + + if meta0.isadmin: + return + + allowed0 = meta0.value + + meta1 = self._propAllowedReason(user, prop.setperms[1], gateiden=layriden) + allowed1 = meta1.value + + if allowed0: + if allowed1: + return + elif allowed1 is False: + # This is a allow-with-precedence case. + # Inspect meta to determine if the rule a0 is more specific than rule a1 + if len(meta0.rule) >= len(meta1.rule): + return + user.raisePermDeny(prop.setperms[0], gateiden=layriden) + return + + if allowed1: + if allowed0 is None: + return + # allowed0 here is False. This is a deny-with-precedence case. + # Inspect meta to determine if the rule a1 is more specific than rule a0 + if len(meta1.rule) > len(meta0.rule): + return + + user.raisePermDeny(prop.setperms[0], gateiden=layriden) + + def confirmPropDel(self, user, prop, layriden): + meta0 = self._propAllowedReason(user, prop.delperms[0], gateiden=layriden) + + if meta0.isadmin: + return + + allowed0 = meta0.value + meta1 = self._propAllowedReason(user, prop.delperms[1], gateiden=layriden) + allowed1 = meta1.value + + if allowed0: + if allowed1: + return + elif allowed1 is False: + # This is a allow-with-precedence case. + # Inspect meta to determine if the rule a0 is more specific than rule a1 + if len(meta0.rule) >= len(meta1.rule): + return + user.raisePermDeny(prop.delperms[0], gateiden=layriden) + return + + if allowed1: + if allowed0 is None: + return + # allowed0 here is False. This is a deny-with-precedence case. + # Inspect meta to determine if the rule a1 is more specific than rule a0 + if len(meta1.rule) > len(meta0.rule): + return + + user.raisePermDeny(prop.delperms[0], gateiden=layriden) + @contextlib.asynccontextmanager async def getTempCortex(mods=None): ''' diff --git a/synapse/lib/coro.py b/synapse/lib/coro.py index 6097093c017..fc4706aaca4 100644 --- a/synapse/lib/coro.py +++ b/synapse/lib/coro.py @@ -39,7 +39,7 @@ async def agen(item): for x in item: yield x -async def pause(genr, iterations=1000): +async def pause(genr, iterations=10): idx = 0 async for out in agen(genr): diff --git a/synapse/lib/layer.py b/synapse/lib/layer.py index 52b78f4b91c..9df33318a7f 100644 --- a/synapse/lib/layer.py +++ b/synapse/lib/layer.py @@ -4094,91 +4094,120 @@ async def iterNodeDataKeys(self, buid): prop = self.getAbrvProp(abrv) yield prop[0] - async def iterLayerAddPerms(self): + async def confirmLayerEditPerms(self, user, gateiden, delete=False): + if user.allowed(('node',), gateiden=gateiden): + return + + if delete: + perm_forms = ('node', 'del') + perm_props = ('node', 'prop', 'del') + perm_tags = ('node', 'tag', 'del') + perm_ndata = ('node', 'data', 'pop') + perm_edges = ('node', 'edge', 'del') + else: + perm_forms = ('node', 'add') + perm_props = ('node', 'prop', 'set') + perm_tags = ('node', 'tag', 'add') + perm_ndata = ('node', 'data', 'set') + perm_edges = ('node', 'edge', 'add') + + allow_forms = user.allowed(perm_forms, gateiden=gateiden) + allow_props = user.allowed(perm_props, gateiden=gateiden) + allow_tags = user.allowed(perm_tags, gateiden=gateiden) + allow_ndata = user.allowed(perm_ndata, gateiden=gateiden) + allow_edges = user.allowed(perm_edges, gateiden=gateiden) + + if all((allow_forms, allow_props, allow_tags, allow_ndata, allow_edges)): + return # nodes & props - async for byts, abrv in s_coro.pause(self.propabrv.slab.scanByFull(db=self.propabrv.name2abrv)): - form, prop = s_msgpack.un(byts) - if form is None: - continue + if not allow_forms or not allow_props: + async for byts, abrv in s_coro.pause(self.propabrv.slab.scanByFull(db=self.propabrv.name2abrv)): + form, prop = s_msgpack.un(byts) + if form is None: # pragma: no cover + continue - if self.layrslab.prefexists(abrv, db=self.byprop): - if prop: - yield ('node', 'prop', 'set', f'{form}:{prop}') - else: - yield ('node', 'add', form) + if self.layrslab.prefexists(abrv, db=self.byprop): + if prop and not allow_props: + realform = self.core.model.form(form) + if not realform: # pragma: no cover + mesg = f'Invalid form: {form}' + raise s_exc.NoSuchForm(mesg=mesg, form=form) + + realprop = realform.prop(prop) + if not realprop: # pragma: no cover + mesg = f'Invalid prop: {form}:{prop}' + raise s_exc.NoSuchProp(mesg=mesg, form=form, prop=prop) + + if delete: + self.core.confirmPropDel(user, realprop, gateiden) + else: + self.core.confirmPropSet(user, realprop, gateiden) + + elif not prop and not allow_forms: + user.confirm(perm_forms + (form,), gateiden=gateiden) # tagprops - async for byts, abrv in s_coro.pause(self.tagpropabrv.slab.scanByFull(db=self.tagpropabrv.name2abrv)): - info = s_msgpack.un(byts) - if None in info or len(info) != 3: - continue + if not allow_tags: + async for byts, abrv in s_coro.pause(self.tagpropabrv.slab.scanByFull(db=self.tagpropabrv.name2abrv)): + info = s_msgpack.un(byts) + if None in info or len(info) != 3: + continue - if self.layrslab.prefexists(abrv, db=self.bytagprop): - yield ('node', 'tag', 'add', *info[1].split('.')) + if self.layrslab.prefexists(abrv, db=self.bytagprop): + perm = perm_tags + tuple(info[1].split('.')) + user.confirm(perm, gateiden=gateiden) # nodedata - async for abrv in s_coro.pause(self.dataslab.scanKeys(db=self.dataname)): - name, _ = self.getAbrvProp(abrv) - yield ('node', 'data', 'set', name) + if not allow_ndata: + async for abrv in s_coro.pause(self.dataslab.scanKeys(db=self.dataname)): + name, _ = self.getAbrvProp(abrv) + perm = perm_ndata + (name,) + user.confirm(perm, gateiden=gateiden) # edges - async for verb in s_coro.pause(self.layrslab.scanKeys(db=self.byverb)): - yield ('node', 'edge', 'add', verb.decode()) + if not allow_edges: + async for verb in s_coro.pause(self.layrslab.scanKeys(db=self.byverb)): + perm = perm_edges + (verb.decode(),) + user.confirm(perm, gateiden=gateiden) # tags # NB: tag perms should be yielded for every leaf on every node in the layer - async with self.core.getSpooledDict() as tags: - - # Collect all tag abrvs for all nodes in the layer - async for lkey, buid in s_coro.pause(self.layrslab.scanByFull(db=self.bytag)): - abrv = lkey[:8] - abrvs = list(tags.get(buid, [])) - abrvs.append(abrv) - await tags.set(buid, abrvs) - - # Iterate over each node and it's tags - async for buid, abrvs in s_coro.pause(tags.items()): - seen = {} - - if len(abrvs) == 1: - # Easy optimization: If there's only one tag abrv, then it's a - # leaf by default - name = self.tagabrv.abrvToName(abrv) - key = tuple(name.split('.')) - yield ('node', 'tag', 'add', *key) - - else: - for abrv in abrvs: + if not allow_tags: + async with self.core.getSpooledDict() as tags: + + # Collect all tag abrvs for all nodes in the layer + async for lkey, buid in s_coro.pause(self.layrslab.scanByFull(db=self.bytag)): + abrv = lkey[:8] + abrvs = list(tags.get(buid, [])) + abrvs.append(abrv) + await tags.set(buid, abrvs) + + # Iterate over each node and it's tags + async for buid, abrvs in s_coro.pause(tags.items()): + seen = {} + + if len(abrvs) == 1: + # Easy optimization: If there's only one tag abrv, then it's a + # leaf by default name = self.tagabrv.abrvToName(abrv) - parts = tuple(name.split('.')) - for idx in range(1, len(parts) + 1): - key = tuple(parts[:idx]) - seen.setdefault(key, 0) - seen[key] += 1 - - for key, count in seen.items(): - if count == 1: - yield ('node', 'tag', 'add', *key) - - async def iterLayerDelPerms(self): - async for perm in self.iterLayerAddPerms(): - if perm[:2] == ('node', 'add'): - yield ('node', 'del', *perm[2:]) - continue - - match perm[:3]: - case ('node', 'prop', 'set'): - yield ('node', 'prop', 'del', *perm[3:]) - - case ('node', 'tag', 'add'): - yield ('node', 'tag', 'del', *perm[3:]) + key = tuple(name.split('.')) + perm = perm_tags + key + user.confirm(perm, gateiden=gateiden) - case ('node', 'data', 'set'): - yield ('node', 'data', 'pop', *perm[3:]) - - case ('node', 'edge', 'add'): - yield ('node', 'edge', 'del', *perm[3:]) + else: + for abrv in abrvs: + name = self.tagabrv.abrvToName(abrv) + parts = tuple(name.split('.')) + for idx in range(1, len(parts) + 1): + key = tuple(parts[:idx]) + seen.setdefault(key, 0) + seen[key] += 1 + + for key, count in seen.items(): + if count == 1: + perm = perm_tags + key + user.confirm(perm, gateiden=gateiden) async def iterLayerNodeEdits(self): ''' diff --git a/synapse/lib/storm.py b/synapse/lib/storm.py index 89c14101b5e..20f175f2713 100644 --- a/synapse/lib/storm.py +++ b/synapse/lib/storm.py @@ -2195,92 +2195,28 @@ def allowed(self, perms, gateiden=None, default=None): return self.user.allowed(perms, gateiden=gateiden, default=default) def allowedReason(self, perms, gateiden=None, default=None): - ''' - Similar to allowed, but always prefer the default value specified by the caller. - Default values are still pulled from permdefs if there is a match there; but still prefer caller default. - This results in a ternary response that can be used to know if a rule had a positive/negative or no match. - The matching reason metadata is also returned. - ''' if self.asroot: return self._admin_reason - if default is None: - permdef = self.snap.core.getPermDef(perms) - if permdef: - default = permdef.get('default', default) - - return self.user.getAllowedReason(perms, gateiden=gateiden, default=default) + return self.snap.core._propAllowedReason(self.user, perms, gateiden=gateiden, default=default) def confirmPropSet(self, prop, layriden=None): + if self.asroot: + return if layriden is None: layriden = self.snap.wlyr.iden - meta0 = self.allowedReason(prop.setperms[0], gateiden=layriden) - - if meta0.isadmin: - return - - allowed0 = meta0.value - - meta1 = self.allowedReason(prop.setperms[1], gateiden=layriden) - allowed1 = meta1.value - - if allowed0: - if allowed1: - return - elif allowed1 is False: - # This is a allow-with-precedence case. - # Inspect meta to determine if the rule a0 is more specific than rule a1 - if len(meta0.rule) >= len(meta1.rule): - return - self.user.raisePermDeny(prop.setperms[0], gateiden=layriden) - return - - if allowed1: - if allowed0 is None: - return - # allowed0 here is False. This is a deny-with-precedence case. - # Inspect meta to determine if the rule a1 is more specific than rule a0 - if len(meta1.rule) > len(meta0.rule): - return - - self.user.raisePermDeny(prop.setperms[0], gateiden=layriden) + return self.snap.core.confirmPropSet(self.user, prop, layriden=layriden) def confirmPropDel(self, prop, layriden=None): + if self.asroot: + return if layriden is None: layriden = self.snap.wlyr.iden - meta0 = self.allowedReason(prop.delperms[0], gateiden=layriden) - - if meta0.isadmin: - return - - allowed0 = meta0.value - meta1 = self.allowedReason(prop.delperms[1], gateiden=layriden) - allowed1 = meta1.value - - if allowed0: - if allowed1: - return - elif allowed1 is False: - # This is a allow-with-precedence case. - # Inspect meta to determine if the rule a0 is more specific than rule a1 - if len(meta0.rule) >= len(meta1.rule): - return - self.user.raisePermDeny(prop.delperms[0], gateiden=layriden) - return - - if allowed1: - if allowed0 is None: - return - # allowed0 here is False. This is a deny-with-precedence case. - # Inspect meta to determine if the rule a1 is more specific than rule a0 - if len(meta1.rule) > len(meta0.rule): - return - - self.user.raisePermDeny(prop.delperms[0], gateiden=layriden) + return self.snap.core.confirmPropDel(self.user, prop, layriden=layriden) def confirmEasyPerm(self, item, perm, mesg=None): if not self.asroot: diff --git a/synapse/lib/view.py b/synapse/lib/view.py index ea8743b8318..63103022b7f 100644 --- a/synapse/lib/view.py +++ b/synapse/lib/view.py @@ -1444,10 +1444,7 @@ async def mergeAllowed(self, user=None, force=False): if user is None or user.isAdmin() or user.isAdmin(gateiden=parentlayr.iden): return - async with await self.parent.snap(user=user) as snap: - async for perm in fromlayr.iterLayerAddPerms(): - self.parent._confirm(user, perm) - await asyncio.sleep(0) + await fromlayr.confirmLayerEditPerms(user, parentlayr.iden) async def wipeAllowed(self, user=None): ''' @@ -1457,9 +1454,7 @@ async def wipeAllowed(self, user=None): return layer = self.layers[0] - async for perm in layer.iterLayerDelPerms(): - self._confirm(user, perm) - await asyncio.sleep(0) + await layer.confirmLayerEditPerms(user, layer.iden, delete=True) async def runTagAdd(self, node, tag, valu): diff --git a/synapse/tests/test_lib_layer.py b/synapse/tests/test_lib_layer.py index 0260b2d2da0..6f4d289b2eb 100644 --- a/synapse/tests/test_lib_layer.py +++ b/synapse/tests/test_lib_layer.py @@ -1932,28 +1932,8 @@ async def __anit__(self, dirn=None, size=1, cell=None): $node.data.set(foo, bar) ''', opts=opts) - perms = [perm async for perm in layr.iterLayerAddPerms()] - self.eq({ - ('node', 'add', 'syn:tag'), - ('node', 'add', 'test:str'), - - ('node', 'prop', 'set', 'test:str:hehe'), - ('node', 'prop', 'set', 'test:str:.created'), - - ('node', 'prop', 'set', 'syn:tag:up'), - ('node', 'prop', 'set', 'syn:tag:base'), - ('node', 'prop', 'set', 'syn:tag:depth'), - ('node', 'prop', 'set', 'syn:tag:.created'), - - ('node', 'tag', 'add', 'foo'), - ('node', 'tag', 'add', 'bar'), - ('node', 'tag', 'add', 'foo', 'bar'), - ('node', 'tag', 'add', 'foo', 'bar', 'baz'), - - ('node', 'data', 'set', 'foo'), - - ('node', 'edge', 'add', 'refs'), - }, set(perms)) + parent = core.view.layers[0] + await layr.confirmLayerEditPerms(core.auth.rootuser, parent.iden) await core.nodes(''' test:str=foo @@ -1962,35 +1942,8 @@ async def __anit__(self, dirn=None, size=1, cell=None): | delnode ''', opts=opts) - perms = [perm async for perm in layr.iterLayerAddPerms()] - self.eq({ - ('node', 'add', 'syn:tag'), - ('node', 'add', 'test:str'), - - ('node', 'prop', 'set', 'test:str:.created'), - - ('node', 'prop', 'set', 'syn:tag:up'), - ('node', 'prop', 'set', 'syn:tag:base'), - ('node', 'prop', 'set', 'syn:tag:depth'), - ('node', 'prop', 'set', 'syn:tag:.created'), - - ('node', 'tag', 'add', 'foo', 'bar'), - }, set(perms)) - - perms = [perm async for perm in layr.iterLayerDelPerms()] - self.eq({ - ('node', 'del', 'syn:tag'), - ('node', 'del', 'test:str'), - - ('node', 'prop', 'del', 'test:str:.created'), - - ('node', 'prop', 'del', 'syn:tag:up'), - ('node', 'prop', 'del', 'syn:tag:base'), - ('node', 'prop', 'del', 'syn:tag:depth'), - ('node', 'prop', 'del', 'syn:tag:.created'), - - ('node', 'tag', 'del', 'foo', 'bar'), - }, set(perms)) + await layr.confirmLayerEditPerms(core.auth.rootuser, parent.iden) + await layr.confirmLayerEditPerms(core.auth.rootuser, layr.iden, delete=True) async def test_layer_v9(self): async with self.getRegrCore('2.101.1-hugenum-indxprec') as core: diff --git a/synapse/tests/test_lib_view.py b/synapse/tests/test_lib_view.py index 2dd5179038c..101baa2992e 100644 --- a/synapse/tests/test_lib_view.py +++ b/synapse/tests/test_lib_view.py @@ -769,7 +769,7 @@ async def test_lib_view_merge_perms(self): with self.raises(s_exc.AuthDeny) as cm: await core.nodes('$lib.view.get().merge()', opts=viewopts) - self.eq('node.prop.set.syn:tag:base', cm.exception.errinfo['perm']) + self.eq('node.prop.set.syn:tag.base', cm.exception.errinfo['perm']) await core.addUserRule(useriden, (True, ('node', 'prop', 'set')), gateiden=baselayr)