测试:限定前端权限门禁接收者
This commit is contained in:
@@ -314,10 +314,11 @@ def _extract_static_has_permi_and(expression: str) -> list[str]:
|
|||||||
permission_tokens = list(re.finditer(r'\bhasPermi(?:And|Or)\b', structure))
|
permission_tokens = list(re.finditer(r'\bhasPermi(?:And|Or)\b', structure))
|
||||||
if any(token.group(0) == 'hasPermiOr' for token in permission_tokens):
|
if any(token.group(0) == 'hasPermiOr' for token in permission_tokens):
|
||||||
raise AssertionError('禁止使用 proxy.$auth.hasPermiOr,权限门禁必须使用约定的静态 AND 语义')
|
raise AssertionError('禁止使用 proxy.$auth.hasPermiOr,权限门禁必须使用约定的静态 AND 语义')
|
||||||
call_tokens = list(re.finditer(r'proxy\.\$auth\.hasPermiAnd\s*\(', structure))
|
canonical_call_prefix = r'(?<![\w$.])proxy\.\$auth\.hasPermiAnd\s*\('
|
||||||
|
call_tokens = list(re.finditer(canonical_call_prefix, structure))
|
||||||
if len(permission_tokens) != len(call_tokens):
|
if len(permission_tokens) != len(call_tokens):
|
||||||
raise AssertionError('hasPermiAnd 必须使用 canonical proxy.$auth.hasPermiAnd(static-array) 形式')
|
raise AssertionError('hasPermiAnd 必须使用 canonical proxy.$auth.hasPermiAnd(static-array) 形式')
|
||||||
call_pattern = re.compile(r'proxy\.\$auth\.hasPermiAnd\s*\(\s*(?P<array>\[[^\[\]]*\])\s*\)')
|
call_pattern = re.compile(canonical_call_prefix + r'\s*(?P<array>\[[^\[\]]*\])\s*\)')
|
||||||
calls = list(call_pattern.finditer(structure))
|
calls = list(call_pattern.finditer(structure))
|
||||||
if len(calls) != len(call_tokens):
|
if len(calls) != len(call_tokens):
|
||||||
raise AssertionError('hasPermiAnd 必须直接传入静态字符串数组')
|
raise AssertionError('hasPermiAnd 必须直接传入静态字符串数组')
|
||||||
@@ -517,6 +518,22 @@ class ApiPermissionContractTest(unittest.TestCase):
|
|||||||
):
|
):
|
||||||
_extract_guarded_vue_permissions(source)
|
_extract_guarded_vue_permissions(source)
|
||||||
|
|
||||||
|
def test_vue_guard_parser_rejects_noncanonical_permission_receivers(self) -> None:
|
||||||
|
valid_guard = '<button v-hasPermi="[\'master:strain:list\']">合法门禁</button>'
|
||||||
|
invalid_calls = (
|
||||||
|
"myproxy.$auth.hasPermiAnd(['master:strain:query'])",
|
||||||
|
"foo.proxy.$auth.hasPermiAnd(['master:strain:query'])",
|
||||||
|
"$proxy.$auth.hasPermiAnd(['master:strain:query'])",
|
||||||
|
"this.proxy.$auth.hasPermiAnd(['master:strain:query'])",
|
||||||
|
)
|
||||||
|
for invalid_call in invalid_calls:
|
||||||
|
source = f'{valid_guard}<button v-if="{invalid_call}">错误接收者</button>'
|
||||||
|
with (
|
||||||
|
self.subTest(invalid_call=invalid_call),
|
||||||
|
self.assertRaisesRegex(AssertionError, 'canonical'),
|
||||||
|
):
|
||||||
|
_extract_guarded_vue_permissions(source)
|
||||||
|
|
||||||
def test_independent_expected_permissions_reject_four_layers_missing_same_permission(self) -> None:
|
def test_independent_expected_permissions_reject_four_layers_missing_same_permission(self) -> None:
|
||||||
missing = 'master:strain:query'
|
missing = 'master:strain:query'
|
||||||
mutated = EXPECTED_PERMISSIONS - {missing}
|
mutated = EXPECTED_PERMISSIONS - {missing}
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ function extractStaticHasPermiAnd(expression) {
|
|||||||
!permissionTokens.some((token) => token[0] === 'hasPermiOr'),
|
!permissionTokens.some((token) => token[0] === 'hasPermiOr'),
|
||||||
'禁止使用 proxy.$auth.hasPermiOr,权限门禁必须使用约定的静态 AND 语义'
|
'禁止使用 proxy.$auth.hasPermiOr,权限门禁必须使用约定的静态 AND 语义'
|
||||||
)
|
)
|
||||||
const callPattern = /proxy\.\$auth\.hasPermiAnd\s*\(/g
|
const callPattern = /(?<![\w$.])proxy\.\$auth\.hasPermiAnd\s*\(/g
|
||||||
const canonicalCalls = [...sanitized.structure.matchAll(callPattern)]
|
const canonicalCalls = [...sanitized.structure.matchAll(callPattern)]
|
||||||
assert.equal(
|
assert.equal(
|
||||||
canonicalCalls.length,
|
canonicalCalls.length,
|
||||||
@@ -911,6 +911,21 @@ test('完整合法门禁旁的非 canonical 权限调用必须 fail-closed', ()
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('权限门禁拒绝带前缀的非 canonical proxy 接收者', () => {
|
||||||
|
const validGuard = `<button v-hasPermi="['master:strain:list']">合法门禁</button>`
|
||||||
|
const invalidCalls = [
|
||||||
|
`myproxy.$auth.hasPermiAnd(['master:strain:query'])`,
|
||||||
|
`foo.proxy.$auth.hasPermiAnd(['master:strain:query'])`,
|
||||||
|
`$proxy.$auth.hasPermiAnd(['master:strain:query'])`,
|
||||||
|
`this.proxy.$auth.hasPermiAnd(['master:strain:query'])`
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const invalidCall of invalidCalls) {
|
||||||
|
const source = `${validGuard}<button v-if="${invalidCall}">错误接收者</button>`
|
||||||
|
assert.throws(() => extractGuardedVuePermissions(source), /canonical/)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('静态权限数组拒绝稀疏元素且仅允许单个尾逗号', () => {
|
test('静态权限数组拒绝稀疏元素且仅允许单个尾逗号', () => {
|
||||||
const sparseArrays = [
|
const sparseArrays = [
|
||||||
`[, 'master:strain:list']`,
|
`[, 'master:strain:list']`,
|
||||||
|
|||||||
Reference in New Issue
Block a user