diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0fd6f885..3e82a0b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,7 +29,6 @@
#### Код модулей
-
- 3 проверки на избыточное обращение внутри модуля через его имя или псевдоним ЭтотОбъект (к методу, свойству или реквизиту)
- Проверка использования устаревшего "ЭтаФорма" в модуле формы
- Проверка нарушения схемы работы с транзакциями связанной с фиксацией транзакции:
@@ -46,6 +45,8 @@
1. Mежду "НачатьТранзакцию()" и "Попытка" есть исполняемый код, который может вызвать исключение
2. Не найден оператор "Попытка" после вызова "НачатьТранзакцию()"
- Отсутствует удаление временного файла после использования.
+- Отсутствует включение безопасного режима перед вызовом метода "Выполнить" или "Вычислить"
+
#### Запросы
- В качестве правого операнда операции сравнения "ПОДОБНО" указано поле таблицы
@@ -56,7 +57,6 @@
### Новые быстрые исправления (Quick-fix)
-
- 3 исправления исправления для удаления избыточного обращения внутри модуля к самому себе
- Замена в модуле формы устаревшего свойства "ЭтаФорма" на "ЭтотОбъект"
- Конвертация функции в процедуру
diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml b/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml
index 6250fff5..9f0c599b 100644
--- a/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml
+++ b/bundles/com.e1c.v8codestyle.bsl.ui/plugin.xml
@@ -364,6 +364,9 @@
+
+
diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java
index b562846e..e70d0f9e 100644
--- a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java
+++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/Messages.java
@@ -48,6 +48,10 @@ final class Messages
public static String SelfReferenceFix_details;
+ public static String ServerExecutionSafeModeFix_description;
+
+ public static String ServerExecutionSafeModeFix_details;
+
public static String UndefinedMethodFix_func_title;
public static String UndefinedMethodFix_func_desc;
public static String UndefinedMethodFix_proc_title;
diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/ServerExecutionSafeModeFix.java b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/ServerExecutionSafeModeFix.java
new file mode 100644
index 00000000..3dabc420
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/ServerExecutionSafeModeFix.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (C) 2022, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * 1C-Soft LLC - initial API and implementation
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl.ui.qfix;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.xtext.EcoreUtil2;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
+import org.eclipse.xtext.resource.XtextResource;
+
+import com._1c.g5.v8.dt.bsl.model.ExecuteStatement;
+import com._1c.g5.v8.dt.bsl.model.Statement;
+import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
+import com._1c.g5.v8.dt.common.StringUtils;
+import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
+import com.e1c.g5.v8.dt.bsl.check.qfix.IXtextBslModuleFixModel;
+import com.e1c.g5.v8.dt.bsl.check.qfix.IXtextInteractiveBslModuleFixModel;
+import com.e1c.g5.v8.dt.bsl.check.qfix.SingleVariantXtextBslModuleFix;
+import com.e1c.g5.v8.dt.check.qfix.components.QuickFix;
+
+/**
+ * Quick fix for check com.e1c.v8codestyle.bsl.check:server-execution-safe-mode
+ *
+ * @author Maxim Galios
+ *
+ */
+@QuickFix(checkId = "server-execution-safe-mode", supplierId = "com.e1c.v8codestyle.bsl")
+public class ServerExecutionSafeModeFix
+ extends SingleVariantXtextBslModuleFix
+{
+ private static final String SAFE_MODE_INVOCATION = "SetSafeMode(True);"; //$NON-NLS-1$
+ private static final String SAFE_MODE_INVOCATION_RU = "УстановитьБезопасныйРежим(Истина);"; //$NON-NLS-1$
+
+ @Override
+ protected void configureFix(FixConfigurer configurer)
+ {
+ configurer.interactive(true)
+ .description(Messages.ServerExecutionSafeModeFix_description)
+ .details(Messages.ServerExecutionSafeModeFix_details);
+ }
+
+ @Override
+ protected TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model) throws BadLocationException
+ {
+ EObject element = model.getElement();
+ if (!(element instanceof StaticFeatureAccess) && !(element instanceof ExecuteStatement))
+ {
+ return null;
+ }
+
+ String safeModeStatement =
+ model.getScriptVariant() == ScriptVariant.RUSSIAN ? SAFE_MODE_INVOCATION_RU : SAFE_MODE_INVOCATION;
+
+ INode node = NodeModelUtils.findActualNodeFor(
+ element instanceof StaticFeatureAccess ? EcoreUtil2.getContainerOfType(element, Statement.class) : element);
+
+ IXtextInteractiveBslModuleFixModel interactiveModel = (IXtextInteractiveBslModuleFixModel)model;
+ String indent = interactiveModel.getFormatString(element).orElse(StringUtils.EMPTY);
+
+ String codeToInsert = safeModeStatement + model.getLineSeparator() + indent;
+ return new InsertEdit(node.getOffset(), codeToInsert);
+ }
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties
index d27324ef..fc779b05 100644
--- a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties
+++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages.properties
@@ -25,6 +25,8 @@ OpenBslDocCommentViewFix_Details=Open documentation comment data structure view
OpenBslDocCommentViewFix_Description=Open documentation comment structure view
SelfReferenceFix_description=Remove excessive self reference
SelfReferenceFix_details=Remove excessive self reference
+ServerExecutionSafeModeFix_description = Enable safe mode
+ServerExecutionSafeModeFix_details = Insert safe mode enable statement before "Execute" or "Eval" method call
UndefinedMethodFix_func_title=Create function
UndefinedMethodFix_func_desc=Create a new function in the module
UndefinedMethodFix_proc_title=Create procedure
diff --git a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties
index 76bee16b..dff861b3 100644
--- a/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties
+++ b/bundles/com.e1c.v8codestyle.bsl.ui/src/com/e1c/v8codestyle/bsl/ui/qfix/messages_ru.properties
@@ -33,6 +33,10 @@ SelfReferenceFix_description=Удалить избыточное обращен
SelfReferenceFix_details=Удалить избыточное обращение внутри модуля через псевдоним "ЭтотОбъект"
+ServerExecutionSafeModeFix_description = Включить безопасный режим
+
+ServerExecutionSafeModeFix_details = Добавить включение безопасного режима перед вызовом метода "Выполнить" или "Вычислить"
+
UndefinedMethodFix_func_desc = Создать новую функцию в модуле
UndefinedMethodFix_func_title = Создать функцию
diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/ru/server-execution-safe-mode.md b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/server-execution-safe-mode.md
new file mode 100644
index 00000000..a891ea33
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/markdown/ru/server-execution-safe-mode.md
@@ -0,0 +1,92 @@
+# Отсутствует включение безопасного режима перед вызовом метода "Выполнить" или "Вычислить"
+
+Для исключения описанных уязвимостей, нужно в серверных процедурах и
+функциях вызов методов Выполнить или Вычислить предварять включением безопасного режима.
+
+В режиме сервиса, включение безопасного режима должно учитывать разделение данных.
+
+## Неправильно
+
+```bsl
+Выполнить(Алгоритм);
+```
+
+```bsl
+Вычислить(Алгоритм);
+```
+
+## Правильно
+
+```bsl
+УстановитьБезопасныйРежим(Истина);
+Выполнить(Алгоритм);
+```
+
+```bsl
+УстановитьБезопасныйРежим(Истина);
+Вычислить(Алгоритм);
+```
+
+В режиме сервиса:
+
+```bsl
+УстановитьБезопасныйРежим(Истина);
+
+Для каждого ИмяРазделителя Из РазделителиКонфигурации() Цикл
+ УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина);
+КонецЦикла;
+
+Выполнить(Алгоритм);
+```
+
+```bsl
+УстановитьБезопасныйРежим(Истина);
+
+Для каждого ИмяРазделителя Из РазделителиКонфигурации() Цикл
+ УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина);
+КонецЦикла;
+
+Вычислить(Алгоритм);
+```
+
+При использовании в конфигурации Библиотеки стандартных подсистем, следует использовать:
+
+```bsl
+ОбщегоНазначения.ВыполнитьВБезопасномРежиме()
+```
+
+```bsl
+ОбщегоНазначения.ВычислитьВБезопасномРежиме()
+```
+
+Вместо формирования строки вызова метода модуля и передачи ее в Выполнить:
+```bsl
+ОбщегоНазначения.ВыполнитьМетодКонфигурации()
+```
+
+```bsl
+ОбщегоНазначения.ВыполнитьМетодОбъекта()
+```
+
+При использовании в конфигурации Библиотеки стандартных подсистем версии, меньшей чем 2.4.1, следует использовать:
+
+
+```bsl
+РаботаВБезопасномРежиме.ВыполнитьВБезопасномРежиме()
+```
+
+```bsl
+РаботаВБезопасномРежиме.ВычислитьВБезопасномРежиме()
+```
+
+Вместо формирования строки вызова метода модуля и передачи ее в Выполнить:
+```bsl
+РаботаВБезопасномРежиме.ВыполнитьМетодКонфигурации()
+```
+
+```bsl
+РаботаВБезопасномРежиме.ВыполнитьМетодОбъекта()
+```
+
+## См.
+[Ограничения на использование Выполнить и Вычислить на сервере](https://its.1c.ru/db/v8std#content:770:hdoc:2)
diff --git a/bundles/com.e1c.v8codestyle.bsl/markdown/server-execution-safe-mode.md b/bundles/com.e1c.v8codestyle.bsl/markdown/server-execution-safe-mode.md
new file mode 100644
index 00000000..9113367e
--- /dev/null
+++ b/bundles/com.e1c.v8codestyle.bsl/markdown/server-execution-safe-mode.md
@@ -0,0 +1,93 @@
+# Safe mode is not enabled before "Execute" or "Eval" call
+
+To avoid vulnerabilities, in server procedures and functions,
+enable safe mode before calling the Execute or Eval methods.
+
+In service mode, data separation is to be considered upon
+enabling safe mode.
+
+## Noncompliant Code Example
+
+```bsl
+Execute(Algorithm);
+```
+
+```bsl
+Eval(Algorithm);
+```
+
+## Compliant Solution
+
+```bsl
+SetSafeMode(True);
+Execute(Algorithm);
+```
+
+```bsl
+SetSafeMode(True);
+Eval(Algorithm);
+```
+
+In service mode:
+
+```bsl
+SetSafeMode(True);
+
+For each SeparatorName in ConfigurationSeparators() Do
+ SetDataSeparationSafeMode(SeparatorName, True);
+EndDo;
+
+Execute Algorithm;
+```
+
+```bsl
+SetSafeMode(True);
+
+For each SeparatorName in ConfigurationSeparators() Do
+ SetDataSeparationSafeMode(SeparatorName, True);
+EndDo;
+
+Eval(Algorithm);
+```
+
+If the Standard Subsystems Library is used in the configuration, use the following:
+
+```bsl
+Common.ExecuteInSafeMode()
+```
+
+```bsl
+Common.CalculateInSafeMode()
+```
+
+Instead of generating a string calling the module method and passing it to Execute:
+```bsl
+Common.ExecuteConfigurationMethod()
+```
+
+```bsl
+Common.ExecuteObjectMethod()
+```
+
+If the Standard Subsystems Library version is earlier than 2.4.1, use the following:
+
+
+```bsl
+SafeModeManager.ExecuteInSafeMode()
+```
+
+```bsl
+SafeModeManager.CalculateInSafeMode()
+```
+
+Instead of generating a string calling the module method and passing it to Execute:
+```bsl
+SafeModeManager.ExecuteConfigurationMethod()
+```
+
+```bsl
+SafeModeManager.ExecuteObjectMethod()
+```
+
+## See
+[Restrictions on the use of Run and Eval on the server](https://support.1ci.com/hc/en-us/articles/360011122479-Restrictions-on-the-use-of-Run-and-Eval-on-the-server)
diff --git a/bundles/com.e1c.v8codestyle.bsl/plugin.xml b/bundles/com.e1c.v8codestyle.bsl/plugin.xml
index e701d211..98a82f0a 100644
--- a/bundles/com.e1c.v8codestyle.bsl/plugin.xml
+++ b/bundles/com.e1c.v8codestyle.bsl/plugin.xml
@@ -258,6 +258,10 @@
+
+
EVAL = Set.of("Eval", "Вычислить"); //$NON-NLS-1$ //$NON-NLS-2$
+ private static final Collection SAFE_MODE_INVOCATIONS = Set.of("УстановитьБезопасныйРежим", "SetSafeMode"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ @Override
+ public String getCheckId()
+ {
+ return CHECK_ID;
+ }
+
+ @Override
+ protected void configureCheck(CheckConfigurer builder)
+ {
+ builder.title(Messages.ServerExecutionSafeModeCheck_title)
+ .description(Messages.ServerExecutionSafeModeCheck_description)
+ .complexity(CheckComplexity.NORMAL)
+ .severity(IssueSeverity.MAJOR)
+ .issueType(IssueType.SECURITY)
+ .extension(new StandardCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID))
+ .module()
+ .checkedObjectType(INVOCATION)
+ .checkedObjectType(EXECUTE_STATEMENT);
+ }
+
+ @Override
+ protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
+ IProgressMonitor monitor)
+ {
+ EObject eObject = (EObject)object;
+ if (!isServerCall(eObject) || (!isExecute(eObject) && !isEval(eObject)))
+ {
+ return;
+ }
+
+ if (!isSafeModeEnabledBeforeExecution(eObject, monitor))
+ {
+ if (isExecute(eObject))
+ {
+ resultAceptor.addIssue(Messages.ServerExecutionSafeModeCheck_execute_issue, eObject);
+ }
+ else if (isEval(eObject))
+ {
+ resultAceptor.addIssue(Messages.ServerExecutionSafeModeCheck_eval_issue,
+ ((Invocation)eObject).getMethodAccess());
+ }
+ }
+ }
+
+ private boolean isServerCall(EObject eObject)
+ {
+ Environmental environmental = EcoreUtil2.getContainerOfType(eObject, Environmental.class);
+ Environments environments = environmental.environments();
+ return environments.contains(Environment.SERVER);
+ }
+
+ private boolean isSafeModeEnabledBeforeExecution(EObject eObject, IProgressMonitor monitor)
+ {
+ EObject container = eObject.eContainer();
+
+ while (container != null)
+ {
+ if (monitor.isCanceled())
+ {
+ return true;
+ }
+ Optional isSafeModeEnabledForContainer = isSafeModeEnabledForContainer(container, eObject);
+ if (isSafeModeEnabledForContainer.isPresent())
+ {
+ return isSafeModeEnabledForContainer.get();
+ }
+ container = container.eContainer();
+ }
+ return false;
+ }
+
+ private Optional isSafeModeEnabledForContainer(EObject container, EObject eObject)
+ {
+ if (container instanceof IfStatement)
+ {
+ return isSafeModeEnabledForIfStatement((IfStatement)container, eObject);
+ }
+ else if (container instanceof LoopStatement)
+ {
+ return isSafeModeEnabledForLoopStatement((LoopStatement)container, eObject);
+ }
+ else if (container instanceof TryExceptStatement)
+ {
+ return isSafeModeEnabledForTryExceptStatement((TryExceptStatement)container, eObject);
+ }
+ else if (container instanceof Block)
+ {
+ return isSafeModeEnabledForBlock((Block)container, eObject);
+ }
+
+ return Optional.empty();
+ }
+
+ private Optional isSafeModeEnabledForIfStatement(IfStatement ifStatement, EObject eObject)
+ {
+ List ifStatements = ifStatement.getIfPart().getStatements();
+ Optional ifStatementSafeModeEnabled = isSafeModeEnabledInStatementList(ifStatements, eObject);
+
+ if (ifStatementSafeModeEnabled.isPresent())
+ {
+ return ifStatementSafeModeEnabled;
+ }
+
+ List elseIfParts = ifStatement.getElsIfParts();
+ for (Conditional part : elseIfParts)
+ {
+ List elseIfStatements = part.getStatements();
+ Optional elseIfStatementSafeModeEnabled =
+ isSafeModeEnabledInStatementList(elseIfStatements, eObject);
+
+ if (elseIfStatementSafeModeEnabled.isPresent())
+ {
+ return elseIfStatementSafeModeEnabled;
+ }
+ }
+
+ List elseStatements = ifStatement.getElseStatements();
+ return isSafeModeEnabledInStatementList(elseStatements, eObject);
+ }
+
+ private Optional isSafeModeEnabledForLoopStatement(LoopStatement loopStatement, EObject eObject)
+ {
+ List loopStatements = loopStatement.getStatements();
+ return isSafeModeEnabledInStatementList(loopStatements, eObject);
+ }
+
+ private Optional isSafeModeEnabledForTryExceptStatement(TryExceptStatement tryExceptStatement,
+ EObject eObject)
+ {
+ List tryStatements = tryExceptStatement.getTryStatements();
+ Optional tryStatementSafeModeEnabled = isSafeModeEnabledInStatementList(tryStatements, eObject);
+
+ if (tryStatementSafeModeEnabled.isPresent())
+ {
+ return tryStatementSafeModeEnabled;
+ }
+
+ List exceptStatements = tryExceptStatement.getExceptStatements();
+ return isSafeModeEnabledInStatementList(exceptStatements, eObject);
+ }
+
+ private Optional isSafeModeEnabledForBlock(Block block, EObject eObject)
+ {
+ List statements = block.allStatements();
+ return isSafeModeEnabledInStatementList(statements, eObject);
+ }
+
+ private Optional isSafeModeEnabledInStatementList(List statements, EObject eObject)
+ {
+ int executeIndex = findExecuteStatementIndex(statements, eObject);
+ if (executeIndex == -1)
+ {
+ return Optional.empty();
+ }
+
+ for (int i = executeIndex - 1; i >= 0; i--)
+ {
+ Statement statement = statements.get(i);
+ Optional safeModeEnabled = isSafeModeEnabled(statement);
+ if (safeModeEnabled.isPresent())
+ {
+ return safeModeEnabled;
+ }
+ }
+ return Optional.empty();
+ }
+
+ private Optional isSafeModeEnabled(Statement statement)
+ {
+ if (statement instanceof SimpleStatement && isSafeModeMethod(statement))
+ {
+ return Optional.of(isSafeModeEnabledStatement(statement));
+ }
+ else if (statement instanceof IfStatement)
+ {
+ List> safeModeStatementResults = new ArrayList<>();
+ IfStatement ifStatement = (IfStatement)statement;
+
+ List ifStatements = ifStatement.getIfPart().getStatements();
+ safeModeStatementResults.add(safeModeStatementResult(ifStatements));
+
+ List elseIfParts = ifStatement.getElsIfParts();
+ for (Conditional part : elseIfParts)
+ {
+ List elseIfStatements = part.getStatements();
+ safeModeStatementResults.add(safeModeStatementResult(elseIfStatements));
+ }
+
+ List elseStatements = ifStatement.getElseStatements();
+ safeModeStatementResults.add(safeModeStatementResult(elseStatements));
+
+ return validateSafeModeStatements(safeModeStatementResults);
+ }
+ else if (statement instanceof LoopStatement)
+ {
+ LoopStatement loopStatement = (LoopStatement)statement;
+ List loopStatements = loopStatement.getStatements();
+ return safeModeStatementResult(loopStatements);
+ }
+ else if (statement instanceof TryExceptStatement)
+ {
+ List> safeModeStatementResults = new ArrayList<>();
+ TryExceptStatement tryExceptStatement = (TryExceptStatement)statement;
+ List tryStatements = tryExceptStatement.getTryStatements();
+ safeModeStatementResults.add(safeModeStatementResult(tryStatements));
+
+ List exceptStatements = tryExceptStatement.getExceptStatements();
+ safeModeStatementResults.add(safeModeStatementResult(exceptStatements));
+
+ return validateSafeModeStatements(safeModeStatementResults);
+ }
+ return Optional.empty();
+ }
+
+ private Optional safeModeStatementResult(List statements)
+ {
+ for (int i = statements.size() - 1; i >= 0; i--)
+ {
+ Statement statement = statements.get(i);
+ Optional res = isSafeModeEnabled(statement);
+ if (res.isPresent())
+ {
+ return res;
+ }
+ }
+ return Optional.empty();
+ }
+
+ private Optional validateSafeModeStatements(List> safeModeStatements)
+ {
+ if (safeModeStatements.stream().allMatch(Optional::isEmpty))
+ {
+ return Optional.empty();
+ }
+ if (safeModeStatements.stream().filter(Optional::isPresent).anyMatch(s -> !s.get()))
+ {
+ return Optional.of(false);
+ }
+ if (safeModeStatements.stream().allMatch(s -> s.isPresent() && s.get()))
+ {
+ return Optional.of(true);
+ }
+ return Optional.empty();
+ }
+
+ private boolean isSafeModeMethod(Statement statement)
+ {
+ if (!(statement instanceof SimpleStatement))
+ {
+ return false;
+ }
+
+ SimpleStatement simpleStatement = (SimpleStatement)statement;
+ Expression leftExpression = simpleStatement.getLeft();
+ if (!(leftExpression instanceof Invocation))
+ {
+ return false;
+ }
+
+ Invocation invocation = (Invocation)leftExpression;
+ String name = invocation.getMethodAccess().getName();
+ List params = invocation.getParams();
+
+ return SAFE_MODE_INVOCATIONS.stream().anyMatch(st -> st.equalsIgnoreCase(name)) && params.size() == 1
+ && params.get(0) instanceof BooleanLiteral;
+ }
+
+ private int findExecuteStatementIndex(List statements, EObject eObject)
+ {
+ if (eObject instanceof ExecuteStatement)
+ {
+ int index = statements.indexOf(eObject);
+ if (index != -1)
+ {
+ return index;
+ }
+ }
+
+ Statement statement = EcoreUtil2.getContainerOfType(eObject, Statement.class);
+
+ while (statement != null)
+ {
+ int statementIndex = statements.indexOf(statement);
+ if (statementIndex != -1)
+ {
+ return statementIndex;
+ }
+ statement = EcoreUtil2.getContainerOfType(statement.eContainer(), Statement.class);
+ }
+
+ return -1;
+ }
+
+ private boolean isSafeModeEnabledStatement(Statement statement)
+ {
+ if (statement == null)
+ {
+ return false;
+ }
+ SimpleStatement simpleStatement = (SimpleStatement)statement;
+ Invocation invocation = (Invocation)simpleStatement.getLeft();
+
+ List params = invocation.getParams();
+ return ((BooleanLiteral)params.get(0)).isIsTrue();
+ }
+
+ private boolean isExecute(EObject eObject)
+ {
+ return eObject instanceof ExecuteStatement;
+ }
+
+ private boolean isEval(EObject eObject)
+ {
+ return eObject instanceof Invocation && EVAL.stream()
+ .anyMatch(statement -> statement.equalsIgnoreCase(((Invocation)eObject).getMethodAccess().getName()));
+ }
+}
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties
index 7c8e19f9..0d46e2f5 100644
--- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages.properties
@@ -273,6 +273,14 @@ SelfReferenceCheck_Title=Excessive self reference
SelfReferenceCheck_Issue=Excessive usage of self reference (when referencing method, property or attribute)
+ServerExecutionSafeModeCheck_description = Safe mode is not enabled when calling "Execute" or "Eval'
+
+ServerExecutionSafeModeCheck_eval_issue = Safe mode is not enabled when calling "Eval"
+
+ServerExecutionSafeModeCheck_execute_issue = Safe mode is not enabled when calling "Execute"
+
+ServerExecutionSafeModeCheck_title = Safe mode is not enabled when calling "Execute" or "Eval"
+
StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys = Maximum structure constructor keys
StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys = Structure constructor has more than {0} keys
diff --git a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties
index ccacac0a..a5232c87 100644
--- a/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties
+++ b/bundles/com.e1c.v8codestyle.bsl/src/com/e1c/v8codestyle/bsl/check/messages_ru.properties
@@ -278,6 +278,14 @@ SelfReferenceCheck_Title=Избыточное использование псе
SelfReferenceCheck_Issue=Избыточное обращение внутри модуля через псевдоним "ЭтотОбъект" (к методу, свойству или реквизиту)
+ServerExecutionSafeModeCheck_description = Отсутствует включение безопасного режима перед вызовом метода "Выполнить" или "Вычислить"
+
+ServerExecutionSafeModeCheck_eval_issue = Отсутствует включение безопасного режима перед вызовом метода "Вычислить"
+
+ServerExecutionSafeModeCheck_execute_issue = Отсутствует включение безопасного режима перед вызовом метода "Выполнить"
+
+ServerExecutionSafeModeCheck_title = Отсутствует включение безопасного режима перед вызовом метода "Выполнить" или "Вычислить"
+
StructureCtorTooManyKeysCheck_Maximum_structure_constructor_keys = Максимальное количество ключей структуры в конструкторе
StructureCtorTooManyKeysCheck_Structure_constructor_has_more_than__0__keys = Конструктор структуры содержит более чем {0} ключей
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/ServerExecutionSafeModeCheckTest.java b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/ServerExecutionSafeModeCheckTest.java
new file mode 100644
index 00000000..d834a122
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/src/com/e1c/v8codestyle/bsl/check/itests/ServerExecutionSafeModeCheckTest.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (C) 2022, 1C-Soft LLC and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * 1C-Soft LLC - initial API and implementation
+ *******************************************************************************/
+package com.e1c.v8codestyle.bsl.check.itests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.Path;
+import org.junit.Test;
+
+import com._1c.g5.v8.dt.validation.marker.IExtraInfoKeys;
+import com._1c.g5.v8.dt.validation.marker.Marker;
+import com.e1c.v8codestyle.bsl.check.ServerExecutionSafeModeCheck;
+
+/**
+ * The test for class {@link ServerExecutionSafeModeCheck}.
+ *
+ * @author Maxim Galios
+ *
+ */
+public class ServerExecutionSafeModeCheckTest
+ extends AbstractSingleModuleTestBase
+{
+
+ private static final String PROJECT_NAME = "ServerExecutionSafeModeCheck";
+
+ private static final String COMMON_MODULE_SERVER_CALL_FILE_NAME =
+ "/src/CommonModules/CommonModuleServerCall/Module.bsl";
+
+ private static final String COMMON_MODULE_FILE_NAME = "/src/CommonModules/CommonModule/Module.bsl";
+
+ private static final String FORM_MODULE_FILE_NAME = "/src/CommonForms/Form/Module.bsl";
+
+ public ServerExecutionSafeModeCheckTest()
+ {
+ super(ServerExecutionSafeModeCheck.class);
+ }
+
+ @Override
+ protected String getTestConfigurationName()
+ {
+ return PROJECT_NAME;
+ }
+
+ /**
+ * Test that warning is not shown without Server in Environment
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCommonModule() throws Exception
+ {
+ List markers = getMarkers(COMMON_MODULE_FILE_NAME);
+ assertEquals(0, markers.size());
+ }
+
+ /**
+ * Test safe mode is enabled before Execute/Выполнить and Eval/Вычислить in common module
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCommonModuleServerCall() throws Exception
+ {
+ List markers = getMarkers(COMMON_MODULE_SERVER_CALL_FILE_NAME);
+ assertEquals(6, markers.size());
+
+ assertEquals("4", markers.get(0).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("5", markers.get(1).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("11", markers.get(2).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("26", markers.get(3).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("29", markers.get(4).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("30", markers.get(5).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ }
+
+ /**
+ * Test safe mode is enabled before Execute/Выполнить and Eval/Вычислить in form module
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFormModule() throws Exception
+ {
+ List markers = getMarkers(FORM_MODULE_FILE_NAME);
+ assertEquals(4, markers.size());
+
+ assertEquals("4", markers.get(0).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("5", markers.get(1).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("14", markers.get(2).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ assertEquals("15", markers.get(3).getExtraInfo().get(IExtraInfoKeys.TEXT_EXTRA_INFO_LINE_KEY));
+ }
+
+ private List getMarkers(String moduleFileName)
+ {
+ String moduleId = Path.ROOT.append(getTestConfigurationName()).append(moduleFileName).toString();
+ List markers = List.of(markerManager.getMarkers(getProject().getWorkspaceProject(), moduleId));
+
+ String checkId = getCheckId();
+
+ assertNotNull(checkId);
+ return markers.stream()
+ .filter(marker -> checkId.equals(getCheckIdFromMarker(marker, getProject())))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.project b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.project
new file mode 100644
index 00000000..c132e650
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.project
@@ -0,0 +1,18 @@
+
+
+ ServerExecutionSafeModeCheck
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextNature
+ com._1c.g5.v8.dt.core.V8ConfigurationNature
+
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.autosort.prefs b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.autosort.prefs
new file mode 100644
index 00000000..23b06250
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.autosort.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+topObjects=true
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.bsl.prefs b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.bsl.prefs
new file mode 100644
index 00000000..ac5ba525
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.bsl.prefs
@@ -0,0 +1,3 @@
+addModuleStrictTypesAnnotation=false
+createModuleStructure=false
+eclipse.preferences.version=1
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.prefs b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.prefs
new file mode 100644
index 00000000..9e9b57e5
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/com.e1c.v8codestyle.prefs
@@ -0,0 +1,3 @@
+commonChecks=true
+eclipse.preferences.version=1
+standardChecks=true
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/org.eclipse.core.resources.prefs b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..99f26c02
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/DT-INF/PROJECT.PMF b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/DT-INF/PROJECT.PMF
new file mode 100644
index 00000000..e2a20317
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/DT-INF/PROJECT.PMF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Runtime-Version: 8.3.21
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Form.form b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Form.form
new file mode 100644
index 00000000..5e856847
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Form.form
@@ -0,0 +1,26 @@
+
+
+
+ FormCommandBar
+ -1
+ true
+ true
+
+ true
+
+ Left
+ true
+
+ true
+ true
+ Vertical
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Form.mdo b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Form.mdo
new file mode 100644
index 00000000..1ae3e2f5
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Form.mdo
@@ -0,0 +1,10 @@
+
+
+ Form
+
+ en
+ Form
+
+ PersonalComputer
+ MobileDevice
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Module.bsl b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Module.bsl
new file mode 100644
index 00000000..6dc469a5
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonForms/Form/Module.bsl
@@ -0,0 +1,19 @@
+&НаСервере
+Процедура Тест1()
+ Код = "Рез = 1 + 1";
+ Выполнить(Код);
+ а = Вычислить(Код);
+ УстановитьБезопасныйРежим(Истина);
+ Выполнить(Код);
+ а = Вычислить(Код);
+КонецПроцедуры
+
+&AtServer
+Функция Тест2()
+ Код = "Рез = 1 + 1";
+ Execute(Код);
+ а = Eval(Код);
+ SetSafeMode(True);
+ Execute(Код);
+ а = Eval(Код);
+КонецФункции
\ No newline at end of file
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModule/CommonModule.mdo b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModule/CommonModule.mdo
new file mode 100644
index 00000000..a7715d65
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModule/CommonModule.mdo
@@ -0,0 +1,10 @@
+
+
+ CommonModule
+
+ en
+ Common module
+
+ true
+ true
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModule/Module.bsl b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModule/Module.bsl
new file mode 100644
index 00000000..223ab0c5
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModule/Module.bsl
@@ -0,0 +1,5 @@
+Функция Тест()
+ Код = "Рез = 1 + 1";
+ Выполнить(Код);
+ а = 1 + Вычислить(Код);
+КонецФункции
\ No newline at end of file
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModuleServerCall/CommonModuleServerCall.mdo b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModuleServerCall/CommonModuleServerCall.mdo
new file mode 100644
index 00000000..296a737f
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModuleServerCall/CommonModuleServerCall.mdo
@@ -0,0 +1,10 @@
+
+
+ CommonModuleServerCall
+
+ en
+ Common module
+
+ true
+ true
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModuleServerCall/Module.bsl b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModuleServerCall/Module.bsl
new file mode 100644
index 00000000..61351864
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/CommonModules/CommonModuleServerCall/Module.bsl
@@ -0,0 +1,42 @@
+Функция Тест()
+ Код = "Рез = 1 + 1";
+ УстановитьБезопасныйРежим(Ложь);
+ Выполнить(Код);
+ a = Вычислить(Код);
+
+ Попытка
+ SetSafeMode(True);
+ Выполнить(Код);
+ Исключение
+ а = 1 + Вычислить(Код);
+ SetSafeMode(True);
+ КонецПопытки;
+
+ Выполнить(Код);
+ а = а + Вычислить(Код);
+
+ Если 1 > 0 Тогда
+ Для Счетчик = 1 По 5 Цикл
+ а = 1 + Вычислить(Код);
+ КонецЦикла;
+ ИначеЕсли 1 = 0 Тогда
+ Выполнить(Код);
+ Иначе
+ SetSafeMode(False);
+ а = 1 + Вычислить(Код);
+ КонецЕсли;
+
+ Выполнить(Код);
+ а = а + Вычислить(Код);
+
+ Если 1 > 0 Тогда
+ Для Счетчик = 1 По 5 Цикл
+ УстановитьБезопасныйРежим(Истина);
+ КонецЦикла;
+ Иначе
+ УстановитьБезопасныйРежим(Истина);
+ КонецЕсли;
+
+ Execute(Код);
+ а = 1 + Eval(Код);
+КонецФункции
\ No newline at end of file
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/CommandInterface.cmi b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/CommandInterface.cmi
new file mode 100644
index 00000000..0cf6de8a
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/CommandInterface.cmi
@@ -0,0 +1,2 @@
+
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/Configuration.mdo b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/Configuration.mdo
new file mode 100644
index 00000000..ef3fa206
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/Configuration.mdo
@@ -0,0 +1,44 @@
+
+
+ ServerExecutionSafeModeCheck
+
+ en
+ Server execution safe mode check
+
+
+
+
+
+
+
+
+ 8.3.21
+ ManagedApplication
+ PersonalComputer
+
+
+
+
+
+ OSBackup
+
+
+
+ Language.English
+ Managed
+ NotAutoFree
+ DontUse
+ DontUse
+ 8.3.21
+
+ English
+
+ en
+ English
+
+ en
+
+ CommonModule.CommonModule
+ CommonModule.CommonModuleServerCall
+ CommonForm.Form
+
diff --git a/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/MainSectionCommandInterface.cmi b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/MainSectionCommandInterface.cmi
new file mode 100644
index 00000000..0cf6de8a
--- /dev/null
+++ b/tests/com.e1c.v8codestyle.bsl.itests/workspace/ServerExecutionSafeModeCheck/src/Configuration/MainSectionCommandInterface.cmi
@@ -0,0 +1,2 @@
+
+