diff --git a/.claude/skills/role-edit/SKILL.md b/.claude/skills/role-edit/SKILL.md
index 7e5837def..9003e0df1 100644
--- a/.claude/skills/role-edit/SKILL.md
+++ b/.claude/skills/role-edit/SKILL.md
@@ -20,7 +20,7 @@ allowed-tools:
|----------|----------|
| `RolePath` | Каталог роли, `Roles/Имя.xml` или `Roles/Имя/Ext/Rights.xml` |
| `Operation` | Операция из таблицы ниже (альтернатива `DefinitionFile`) |
-| `Value` | Значение операции. Пакет через `;;`. `@путь` — взять значение из файла |
+| `Value` | Значение операции. Пакет через `;;`. Текст можно взять из файла: `@путь` в позиции значения |
| `DefinitionFile` | JSON-массив операций `[{ "operation": "...", "value": "..." }]` |
| `NoValidate` | Не запускать `role-validate` после правки |
@@ -86,10 +86,19 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/role-edit.ps1" -Rol
... -Operation set-rls -Value "Catalog.Товары.Read[Ссылка, Код, Наименование]: "
```
-Строка с тем же набором полей заменяется, с другим — добавляется. Многострочное условие передавай
-файлом: `-Value "@условие.txt"` (в этом режиме `;;` считается текстом, а не разделителем пакета).
+Строка с тем же набором полей заменяется, с другим — добавляется.
Ограничение на невыданное право — ошибка: платформа такое молча игнорирует.
+Длинное условие держи в файле — адрес остаётся в команде, из файла приходит только текст:
+
+```powershell
+... -Operation set-rls -Value "Catalog.Товары.Read: @условие.txt"
+... -Operation add-template -Value "ПоОрганизации(Мод): @условие.txt"
+```
+
+Так же берётся текст у `set-synonym` и `set-comment`: `-Value "@текст.txt"`. Разделитель пакета
+`;;` внутри файла остаётся обычным текстом.
+
Ссылка на шаблон — `#ИмяШаблона("")`; `&` в условиях экранируется автоматически.
## Верификация
diff --git a/.claude/skills/role-edit/scripts/role-edit.ps1 b/.claude/skills/role-edit/scripts/role-edit.ps1
index 869e65361..d42250f5d 100644
--- a/.claude/skills/role-edit/scripts/role-edit.ps1
+++ b/.claude/skills/role-edit/scripts/role-edit.ps1
@@ -1405,18 +1405,18 @@ $script:rightsPath = $script:paths.RightsPath
$script:roleXmlPath = $script:paths.RoleXmlPath
$script:configRoot = $script:paths.ConfigRoot
-# -Value "@путь" — содержимое берётся из файла: так передают многострочное условие RLS,
-# которое инлайном ломается о кавычки и о разделитель пакета.
-$script:valueFromFile = $false
-if ($Value -and $Value.StartsWith("@")) {
- $valueFile = $Value.Substring(1)
+# "@путь" в позиции ТЕКСТА (условие RLS, тело шаблона, синоним) — содержимое берётся из файла:
+# многострочное условие инлайном ломается о кавычки и о разделитель пакета. Адрес при этом
+# остаётся в команде: "Catalog.Товары.Read: @условие.txt".
+function Resolve-TextValue([string]$text) {
+ if (-not $text -or -not $text.StartsWith("@")) { return $text }
+ $valueFile = $text.Substring(1).Trim()
if (-not [System.IO.Path]::IsPathRooted($valueFile)) { $valueFile = Join-Path (Get-Location).Path $valueFile }
if (-not (Test-Path -LiteralPath $valueFile -PathType Leaf)) {
- [Console]::Error.WriteLine("[role-edit] Файл значения не найден: $valueFile")
- exit 1
+ Add-ValidationError "Файл значения не найден: $valueFile"
+ return $text
}
- $Value = [System.IO.File]::ReadAllText($valueFile).Trim()
- $script:valueFromFile = $true
+ return [System.IO.File]::ReadAllText($valueFile).Trim()
}
if ($DefinitionFile -and $Operation) {
@@ -1453,8 +1453,7 @@ function Add-Note([string]$text) { $script:notes += $text }
# --- Разбор значений операций ---
function Parse-BatchValue([string]$val) {
- # Значение из файла не режем: там живут многострочные условия, в которых ';;' — просто текст.
- if ($script:valueFromFile) { return ,@($val) }
+ # Делим ДО чтения файлов, поэтому ';;' внутри условия из файла разделителем не становится.
return @($val -split ';;' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
}
@@ -1539,7 +1538,7 @@ function Parse-RlsAddress([string]$text, [switch]$ConditionRequired) {
Add-ValidationError "$text : разобрано как объект '$objName' и право '$rightName'"
return $null
}
- return @{ Object = $objName; Right = $rightName; Fields = $fields; Condition = $condition }
+ return @{ Object = $objName; Right = $rightName; Fields = $fields; Condition = (Resolve-TextValue $condition) }
}
# "Имя(Пар1, Пар2): условие" — скобки принадлежат имени шаблона, разделитель ищем вне них.
@@ -1550,7 +1549,7 @@ function Parse-TemplateSpec([string]$text, [switch]$NameOnly) {
Add-ValidationError "$text : ожидается 'Имя(Параметры): условие'"
return $null
}
- return @{ Name = $split.Left; Condition = $split.Right }
+ return @{ Name = $split.Left; Condition = (Resolve-TextValue $split.Right) }
}
# --- Доступ к дереву прав ---
@@ -2222,8 +2221,8 @@ foreach ($op in $operations) {
"set-template" { Do-SetTemplate $opValue }
"remove-template" { Do-RemoveTemplate $opValue }
"modify-property" { Do-ModifyProperty $opValue }
- "set-synonym" { $script:pendingMeta += ,@{ Field = 'Synonym'; Text = $opValue } }
- "set-comment" { $script:pendingMeta += ,@{ Field = 'Comment'; Text = $opValue } }
+ "set-synonym" { $script:pendingMeta += ,@{ Field = 'Synonym'; Text = (Resolve-TextValue $opValue) } }
+ "set-comment" { $script:pendingMeta += ,@{ Field = 'Comment'; Text = (Resolve-TextValue $opValue) } }
default {
Add-ValidationError "Неизвестная операция: $opName"
}
diff --git a/.claude/skills/role-edit/scripts/role-edit.py b/.claude/skills/role-edit/scripts/role-edit.py
index bcbe40eb5..0f5961602 100644
--- a/.claude/skills/role-edit/scripts/role-edit.py
+++ b/.claude/skills/role-edit/scripts/role-edit.py
@@ -1461,9 +1461,8 @@ def resolve_role_paths(input_path):
class Editor:
"""Состояние правки: дерево прав, счётчики, отложенные операции."""
- def __init__(self, paths, value_from_file):
+ def __init__(self, paths):
self.paths = paths
- self.value_from_file = value_from_file
parser = etree.XMLParser(remove_blank_text=False)
self.tree = etree.parse(paths["RightsPath"], parser)
self.root = self.tree.getroot()
@@ -1484,11 +1483,25 @@ class Editor:
# --- Разбор значений операций ---
def parse_batch(self, value):
- # Значение из файла не режем: там живут многострочные условия, в которых ';;' — просто текст.
- if self.value_from_file:
- return [value]
+ # Делим ДО чтения файлов, поэтому ';;' внутри условия из файла разделителем не становится.
return [part.strip() for part in value.split(";;") if part.strip()]
+ @staticmethod
+ def resolve_text_value(text):
+ """"@путь" в позиции ТЕКСТА (условие RLS, тело шаблона, синоним) — содержимое из файла:
+ многострочное условие инлайном ломается о кавычки и о разделитель пакета. Адрес при этом
+ остаётся в команде: "Catalog.Товары.Read: @условие.txt"."""
+ if not text or not text.startswith("@"):
+ return text
+ value_file = text[1:].strip()
+ if not os.path.isabs(value_file):
+ value_file = os.path.join(os.getcwd(), value_file)
+ if not os.path.isfile(value_file):
+ add_validation_error(f"Файл значения не найден: {value_file}")
+ return text
+ with open(value_file, encoding="utf-8-sig") as f:
+ return f.read().strip()
+
@staticmethod
def split_at_top_level_colon(text, open_char, close_char):
depth = 0
@@ -1552,7 +1565,8 @@ class Editor:
# Показываем разбор: иначе непонятно, что навык откусил не тот сегмент.
add_validation_error(f"{text} : разобрано как объект '{obj_name}' и право '{right_name}'")
return None
- return {"Object": obj_name, "Right": right_name, "Fields": fields, "Condition": condition}
+ return {"Object": obj_name, "Right": right_name, "Fields": fields,
+ "Condition": self.resolve_text_value(condition)}
def parse_template_spec(self, text, name_only=False):
left, right, found = self.split_at_top_level_colon(text, "(", ")")
@@ -1561,7 +1575,7 @@ class Editor:
if not found:
add_validation_error(f"{text} : ожидается 'Имя(Параметры): условие'")
return None
- return {"Name": left, "Condition": right}
+ return {"Name": left, "Condition": self.resolve_text_value(right)}
# --- Доступ к дереву прав ---
@@ -2064,20 +2078,7 @@ def main():
paths = resolve_role_paths(args.RolePath)
- # -Value "@путь" — содержимое берётся из файла: так передают многострочное условие RLS,
- # которое инлайном ломается о кавычки и о разделитель пакета.
value = args.Value
- value_from_file = False
- if value and value.startswith("@"):
- value_file = value[1:]
- if not os.path.isabs(value_file):
- value_file = os.path.join(os.getcwd(), value_file)
- if not os.path.isfile(value_file):
- print(f"[role-edit] Файл значения не найден: {value_file}", file=sys.stderr)
- sys.exit(1)
- with open(value_file, encoding="utf-8-sig") as f:
- value = f.read().strip()
- value_from_file = True
if args.DefinitionFile and args.Operation:
print("[role-edit] Укажите либо -DefinitionFile, либо -Operation, но не оба сразу", file=sys.stderr)
@@ -2089,7 +2090,7 @@ def main():
target_for_guard = paths["RoleXmlPath"] if os.path.isfile(paths["RoleXmlPath"]) else paths["RightsPath"]
assert_edit_allowed(target_for_guard, "editable")
- ed = Editor(paths, value_from_file)
+ ed = Editor(paths)
operations = []
if args.DefinitionFile:
@@ -2148,9 +2149,9 @@ def main():
continue
pending.append((key, {"Name": canonical, "Value": val}))
elif key == "set-synonym":
- pending.append((key, {"Field": "Synonym", "Text": op_value}))
+ pending.append((key, {"Field": "Synonym", "Text": ed.resolve_text_value(op_value)}))
elif key == "set-comment":
- pending.append((key, {"Field": "Comment", "Text": op_value}))
+ pending.append((key, {"Field": "Comment", "Text": ed.resolve_text_value(op_value)}))
else:
add_validation_error(f"Неизвестная операция: {op_name}")
diff --git a/tests/skills/cases/role-edit/error-value-file-missing.json b/tests/skills/cases/role-edit/error-value-file-missing.json
new file mode 100644
index 000000000..dcfc0f7ba
--- /dev/null
+++ b/tests/skills/cases/role-edit/error-value-file-missing.json
@@ -0,0 +1,21 @@
+{
+ "name": "Отказ: файла значения нет",
+ "setup": "fixture:role-base",
+ "cwd": "workDir",
+ "params": {
+ "rolePath": "Roles/Менеджер"
+ },
+ "input": [
+ {
+ "operation": "set-rls",
+ "value": "Catalog.Товары.Read: @нет.txt"
+ }
+ ],
+ "expectError": true,
+ "noSnapshot": "отказ до записи — рабочий каталог равен фикстуре",
+ "expect": {
+ "stderrContains": [
+ "Файл значения не найден"
+ ]
+ }
+}
diff --git a/tests/skills/cases/role-edit/set-rls-from-file.json b/tests/skills/cases/role-edit/set-rls-from-file.json
new file mode 100644
index 000000000..f5252c090
--- /dev/null
+++ b/tests/skills/cases/role-edit/set-rls-from-file.json
@@ -0,0 +1,26 @@
+{
+ "name": "Условие RLS берётся из файла, ;; внутри него не разделитель",
+ "setup": "fixture:role-base",
+ "cwd": "workDir",
+ "params": {
+ "rolePath": "Roles/Менеджер"
+ },
+ "caseFiles": [
+ "условие.txt"
+ ],
+ "input": [
+ {
+ "operation": "set-rls",
+ "value": "Catalog.Товары.Read: @условие.txt"
+ }
+ ],
+ "expect": {
+ "fileContains": {
+ "file": "Roles/Менеджер/Ext/Rights.xml",
+ "text": [
+ "ЗначениеРазрешено",
+ "хвост в тексте"
+ ]
+ }
+ }
+}
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Catalogs/Товары.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Catalogs/Товары.xml
new file mode 100644
index 000000000..292de84c4
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Catalogs/Товары.xml
@@ -0,0 +1,137 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+
+ Товары
+
+
+ ru
+ Товары
+
+
+
+ false
+ HierarchyFoldersAndItems
+ false
+ 2
+ true
+ true
+
+ ToItems
+ 9
+ 25
+ String
+ Variable
+ WholeCatalog
+ false
+ true
+ AsDescription
+
+ Auto
+ InDialog
+ false
+ BothWays
+
+ Catalog.Товары.StandardAttribute.Description
+ Catalog.Товары.StandardAttribute.Code
+
+ Begin
+ DontUse
+ Directly
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+ Managed
+ Use
+
+
+
+
+
+ Use
+ Auto
+ DontUse
+ false
+ false
+
+
+
+
+ Цена
+
+
+ ru
+ Цена
+
+
+
+
+ xs:decimal
+
+ 15
+ 2
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+ DontIndex
+ Use
+ Use
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Catalogs/Товары/Ext/ObjectModule.bsl b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Catalogs/Товары/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Configuration.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Configuration.xml
new file mode 100644
index 000000000..880e20b87
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Configuration.xml
@@ -0,0 +1,256 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+ UUID-012
+ UUID-013
+
+
+ UUID-014
+ UUID-015
+
+
+
+ TestConfig
+
+
+ ru
+ TestConfig
+
+
+
+
+ Version8_3_24
+ ManagedApplication
+
+ PlatformApplication
+
+ Russian
+
+
+
+
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Biometrics
+ true
+
+
+ Location
+ false
+
+
+ BackgroundLocation
+ false
+
+
+ BluetoothPrinters
+ false
+
+
+ WiFiPrinters
+ false
+
+
+ Contacts
+ false
+
+
+ Calendars
+ false
+
+
+ PushNotifications
+ false
+
+
+ LocalNotifications
+ false
+
+
+ InAppPurchases
+ false
+
+
+ PersonalComputerFileExchange
+ false
+
+
+ Ads
+ false
+
+
+ NumberDialing
+ false
+
+
+ CallProcessing
+ false
+
+
+ CallLog
+ false
+
+
+ AutoSendSMS
+ false
+
+
+ ReceiveSMS
+ false
+
+
+ SMSLog
+ false
+
+
+ Camera
+ false
+
+
+ Microphone
+ false
+
+
+ MusicLibrary
+ false
+
+
+ PictureAndVideoLibraries
+ false
+
+
+ AudioPlaybackAndVibration
+ false
+
+
+ BackgroundAudioPlaybackAndVibration
+ false
+
+
+ InstallPackages
+ false
+
+
+ OSBackup
+ true
+
+
+ ApplicationUsageStatistics
+ false
+
+
+ BarcodeScanning
+ false
+
+
+ BackgroundAudioRecording
+ false
+
+
+ AllFilesAccess
+ false
+
+
+ Videoconferences
+ false
+
+
+ NFC
+ false
+
+
+ DocumentScanning
+ false
+
+
+ SpeechToText
+ false
+
+
+ Geofences
+ false
+
+
+ IncomingShareRequests
+ false
+
+
+ AllIncomingShareRequestsTypesProcessing
+ false
+
+
+
+
+
+ Normal
+
+
+ Language.Русский
+
+
+
+
+
+ Managed
+ NotAutoFree
+ DontUse
+ DontUse
+ TaxiEnableVersion8_2
+ DontUse
+ Version8_3_24
+
+
+
+ Русский
+ Менеджер
+ Товары
+ Заказ
+ Загрузка
+ Цены
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка.xml
new file mode 100644
index 000000000..fa5caaf26
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+
+ Загрузка
+
+
+ ru
+ Загрузка
+
+
+
+ true
+
+
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка/Ext/ManagerModule.bsl b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка/Ext/ManagerModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка/Ext/ObjectModule.bsl b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/DataProcessors/Загрузка/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Documents/Заказ.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Documents/Заказ.xml
new file mode 100644
index 000000000..32fa05878
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Documents/Заказ.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+
+ Заказ
+
+
+ ru
+ Заказ
+
+
+
+ true
+
+ String
+ 11
+ Variable
+ Year
+ true
+ true
+
+
+
+ Document.Заказ.StandardAttribute.Number
+
+ Use
+ Begin
+ DontUse
+ Directly
+
+
+
+
+
+
+ Allow
+ Deny
+ AutoDelete
+ WriteSelected
+ AutoFill
+
+ true
+ true
+ false
+
+ Managed
+ Use
+
+
+
+
+
+ Auto
+ DontUse
+ false
+ false
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Documents/Заказ/Ext/ObjectModule.bsl b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Documents/Заказ/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Ext/ClientApplicationInterface.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Ext/ClientApplicationInterface.xml
new file mode 100644
index 000000000..3c1161b2d
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Ext/ClientApplicationInterface.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ UUID-002
+
+
+
+
+ UUID-004
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/InformationRegisters/Цены.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/InformationRegisters/Цены.xml
new file mode 100644
index 000000000..092bf1d11
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/InformationRegisters/Цены.xml
@@ -0,0 +1,261 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+ UUID-006
+ UUID-007
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+ UUID-012
+ UUID-013
+
+
+ UUID-014
+ UUID-015
+
+
+
+ Цены
+
+
+ ru
+ Цены
+
+
+
+ true
+ InDialog
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+ Nonperiodical
+ Independent
+ false
+ false
+ Managed
+ Use
+ false
+ false
+
+
+
+
+
+ DontUse
+ false
+ false
+
+
+
+
+ Цена
+
+
+ ru
+ Цена
+
+
+
+
+ xs:decimal
+
+ 15
+ 2
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+ DontIndex
+ Use
+ Use
+
+
+
+
+ Товар
+
+
+ ru
+ Товар
+
+
+
+
+ cfg:CatalogRef.Товары
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+ false
+ false
+ false
+ DontIndex
+ Use
+ Use
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/InformationRegisters/Цены/Ext/RecordSetModule.bsl b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/InformationRegisters/Цены/Ext/RecordSetModule.bsl
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Languages/Русский.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Languages/Русский.xml
new file mode 100644
index 000000000..37c60d786
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Languages/Русский.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Русский
+
+
+ ru
+ Русский
+
+
+
+ ru
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Roles/Менеджер.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Roles/Менеджер.xml
new file mode 100644
index 000000000..001d4535b
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Roles/Менеджер.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ Менеджер
+
+
+ ru
+ Менеджер
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Roles/Менеджер/Ext/Rights.xml b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Roles/Менеджер/Ext/Rights.xml
new file mode 100644
index 000000000..2398f0079
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/Roles/Менеджер/Ext/Rights.xml
@@ -0,0 +1,96 @@
+
+
+ false
+ true
+ false
+
+
+
+ ДляОбъекта(Мод)
+ ГДЕ Организация = &ТекОрг
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/snapshots/set-rls-from-file/условие.txt b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/условие.txt
new file mode 100644
index 000000000..1efb2e0a5
--- /dev/null
+++ b/tests/skills/cases/role-edit/snapshots/set-rls-from-file/условие.txt
@@ -0,0 +1,2 @@
+ГДЕ ЗначениеРазрешено(Товары.Ссылка)
+ И Организация = &ТекущаяОрганизация ;; хвост в тексте
\ No newline at end of file
diff --git a/tests/skills/cases/role-edit/условие.txt b/tests/skills/cases/role-edit/условие.txt
new file mode 100644
index 000000000..1efb2e0a5
--- /dev/null
+++ b/tests/skills/cases/role-edit/условие.txt
@@ -0,0 +1,2 @@
+ГДЕ ЗначениеРазрешено(Товары.Ссылка)
+ И Организация = &ТекущаяОрганизация ;; хвост в тексте
\ No newline at end of file