From 9702a4c485f293caa3a510e97e2efd62d2925581 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 17 Aug 2026 16:19:55 +0300 Subject: [PATCH] =?UTF-8?q?fix(cfe-validate):=20=D0=BE=D1=81=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BD=D1=8B=D0=B5=20=D1=80=D0=BE=D0=BB=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=B0=D1=8E=D1=82=20=D0=BF=D1=80=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B7=D0=B0=D0=B8=D0=BC=D1=81=D1=82=D0=B2=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5=20=D0=BE=D0=B1=D1=8A=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Платформа: «Назначение прав доступа на заимствованные объекты основными ролями в расширениях недопустимо». Роль вне DefaultRoles так делать вправе, поэтому проверяются только основные. Ловится статически, а по симптому — отказ загрузки расширения — причина не читается. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/skills/cfe-validate/SKILL.md | 2 +- .../cfe-validate/scripts/cfe-validate.ps1 | 65 ++++++++++++++++++- .../cfe-validate/scripts/cfe-validate.py | 58 ++++++++++++++++- 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/.claude/skills/cfe-validate/SKILL.md b/.claude/skills/cfe-validate/SKILL.md index 85c47481..7b14c124 100644 --- a/.claude/skills/cfe-validate/SKILL.md +++ b/.claude/skills/cfe-validate/SKILL.md @@ -10,7 +10,7 @@ allowed-tools: # /cfe-validate — валидация расширения конфигурации (CFE) -Проверяет структурную корректность расширения: XML-формат, свойства, состав, заимствованные объекты. Аналог `/cf-validate`, но для расширений. +Проверяет структурную корректность расширения: XML-формат, свойства, состав, заимствованные объекты, права ролей. Аналог `/cf-validate`, но для расширений. ## Параметры diff --git a/.claude/skills/cfe-validate/scripts/cfe-validate.ps1 b/.claude/skills/cfe-validate/scripts/cfe-validate.ps1 index 60ef4a7d..03320a7c 100644 --- a/.claude/skills/cfe-validate/scripts/cfe-validate.ps1 +++ b/.claude/skills/cfe-validate/scripts/cfe-validate.ps1 @@ -1,4 +1,4 @@ -# cfe-validate v1.10 — Validate 1C configuration extension structure (CFE) (полнота GeneratedType, ТЧ из AdditionalColumns, сверка путей с -ConfigPath) +# cfe-validate v1.11 — Validate 1C configuration extension structure (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -1169,6 +1169,69 @@ if (-not $script:stopped -and $script:borrowedFormsWithTree.Count -gt 0) { } } +# --- Check 15: основные роли расширения не дают прав на заимствованные объекты --- +# Платформа: «Назначение прав доступа на заимствованные объекты основными ролями в +# расширениях недопустимо». Роль вне так делать вправе — проверяем только +# основные. Ловится статически, а по симптому (отказ загрузки) причина не читается. +$defaultRoleNodes = @($cfgNode.SelectNodes("md:Properties/md:DefaultRoles/xr:Item", $ns)) +if ($defaultRoleNodes.Count -gt 0) { + $adoptedCache = @{} + + function Test-ObjectAdopted { + param([string]$typeName, [string]$objName) + $key = "$typeName.$objName" + if ($adoptedCache.ContainsKey($key)) { return $adoptedCache[$key] } + $adoptedCache[$key] = $false + if ($childTypeDirMap.ContainsKey($typeName)) { + $objPath = Join-Path (Join-Path $configDir $childTypeDirMap[$typeName]) "$objName.xml" + if (Test-Path $objPath) { + try { + $objDoc = New-Object System.Xml.XmlDocument + $objDoc.Load($objPath) + $objNs = New-Object System.Xml.XmlNamespaceManager($objDoc.NameTable) + $objNs.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses") + $ob = $objDoc.SelectSingleNode("/md:MetaDataObject/md:$typeName/md:Properties/md:ObjectBelonging", $objNs) + if ($ob -and $ob.InnerText -eq "Adopted") { $adoptedCache[$key] = $true } + } catch {} + } + } + return $adoptedCache[$key] + } + + $check15Ok = $true + $check15Count = 0 + foreach ($rn in $defaultRoleNodes) { + $roleRef = $rn.InnerText + if ($roleRef -notmatch '^Role\.(.+)$') { continue } + $defRoleName = $Matches[1] + $rightsPath = Join-Path (Join-Path (Join-Path $configDir "Roles") $defRoleName) "Ext\Rights.xml" + if (-not (Test-Path $rightsPath)) { continue } + try { + $rDoc = New-Object System.Xml.XmlDocument + $rDoc.Load($rightsPath) + } catch { + continue + } + $rNs = New-Object System.Xml.XmlNamespaceManager($rDoc.NameTable) + $rNs.AddNamespace("r", "http://v8.1c.ru/8.2/roles") + foreach ($nameNode in $rDoc.SelectNodes("/r:Rights/r:object/r:name", $rNs)) { + $fullName = $nameNode.InnerText + $segs = $fullName.Split(".") + # Configuration.* — права самого расширения, не объект; заимствования там нет. + if ($segs.Count -lt 2 -or $segs[0] -eq "Configuration") { continue } + $check15Count++ + if (Test-ObjectAdopted $segs[0] $segs[1]) { + Report-Error ("15. Роль '$defRoleName' входит в DefaultRoles и даёт права на заимствованный $($segs[0]).$($segs[1]) " + + "($fullName): платформа это запрещает. Вынесите такие права в отдельную роль вне DefaultRoles.") + $check15Ok = $false + } + } + } + if ($check15Ok -and $check15Count -gt 0) { + Report-OK "15. Основные роли: прав на заимствованные объекты нет ($check15Count checked)" + } +} + if ($script:stopped) { & $finalize; exit 1 } # --- Breadcrumb: controlled methods (&ИзменениеИКонтроль) drift is not checked here --- diff --git a/.claude/skills/cfe-validate/scripts/cfe-validate.py b/.claude/skills/cfe-validate/scripts/cfe-validate.py index 5a5f6fad..bce5ee85 100644 --- a/.claude/skills/cfe-validate/scripts/cfe-validate.py +++ b/.claude/skills/cfe-validate/scripts/cfe-validate.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# cfe-validate v1.10 — Validate 1C configuration extension XML structure (CFE) (полнота GeneratedType, ТЧ из AdditionalColumns, сверка путей с -ConfigPath) +# cfe-validate v1.11 — Validate 1C configuration extension XML structure (CFE) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills """Validates extension Configuration.xml: root, InternalInfo, extension properties, ChildObjects, borrowed objects.""" import sys, os, argparse, re @@ -1141,6 +1141,62 @@ def main(): if check14_ok: r.ok(f'14. Object paths vs source config: {path_check_count} checked') + # --- Check 15: основные роли расширения не дают прав на заимствованные объекты --- + # Платформа: «Назначение прав доступа на заимствованные объекты основными ролями в + # расширениях недопустимо». Роль вне так делать вправе — проверяем только + # основные. Ловится статически, а по симптому (отказ загрузки) причина не читается. + default_role_nodes = cfg_node.findall('md:Properties/md:DefaultRoles/xr:Item', NS) + if default_role_nodes: + adopted_cache = {} + + def is_object_adopted(type_name, obj_name): + key = f"{type_name}.{obj_name}" + if key in adopted_cache: + return adopted_cache[key] + adopted_cache[key] = False + dir_name = CHILD_TYPE_DIR_MAP.get(type_name) + if dir_name: + obj_path = os.path.join(config_dir, dir_name, obj_name + '.xml') + if os.path.isfile(obj_path): + try: + obj_root = etree.parse(obj_path).getroot() + ob = obj_root.find(f'md:{type_name}/md:Properties/md:ObjectBelonging', NS) + if ob is not None and (ob.text or '') == 'Adopted': + adopted_cache[key] = True + except Exception: + pass + return adopted_cache[key] + + check15_ok = True + check15_count = 0 + roles_ns = {'r': 'http://v8.1c.ru/8.2/roles'} + for rn in default_role_nodes: + m = re.match(r'^Role\.(.+)$', rn.text or '') + if not m: + continue + def_role_name = m.group(1) + rights_path = os.path.join(config_dir, 'Roles', def_role_name, 'Ext', 'Rights.xml') + if not os.path.isfile(rights_path): + continue + try: + rights_root = etree.parse(rights_path).getroot() + except Exception: + continue + for name_node in rights_root.findall('r:object/r:name', roles_ns): + full_name = name_node.text or '' + segs = full_name.split('.') + # Configuration.* — права самого расширения, не объект; заимствования там нет. + if len(segs) < 2 or segs[0] == 'Configuration': + continue + check15_count += 1 + if is_object_adopted(segs[0], segs[1]): + r.error(f"15. Роль '{def_role_name}' входит в DefaultRoles и даёт права на заимствованный " + f"{segs[0]}.{segs[1]} ({full_name}): платформа это запрещает. " + "Вынесите такие права в отдельную роль вне DefaultRoles.") + check15_ok = False + if check15_ok and check15_count > 0: + r.ok(f'15. Основные роли: прав на заимствованные объекты нет ({check15_count} checked)') + if r.stopped: r.finalize(out_file) sys.exit(1)