Compare commits

..

5 Commits

  1. 14
      sonar-keyware-plugins-java/pom.xml
  2. 15
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/JavaSecurityDesignWayProfile.java
  3. 20
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/JavaFileCheckRegistrar.java
  4. 18
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/JavaSecurityDesignRulesRepository.java
  5. 44
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/RulesList.java
  6. 38
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/PasswordInputTagChecker.java
  7. 52
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/RedirectUrlChecker.java
  8. 2
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java
  9. 0
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/Md5PassWordVerifyChecker.html
  10. 9
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordInputTagChecker.html
  11. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordInputTagChecker.json
  12. 0
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/RSAEncryptionChecker.html
  13. 14
      sonar-keyware-plugins-java/src/test/files/PasswordInputTagChecker.html
  14. 2
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/JavaFileCheckRegistrarTest.java
  15. 5
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/JavaSecurityDesignRulesRepositoryTest.java
  16. 35
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/PasswordInputTagCheckerTest.java
  17. 113
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/utils/HtmlCheckMessagesVerifier.java
  18. 43
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/utils/HtmlCheckMessagesVerifierRule.java
  19. 66
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/utils/HtmlTestHelper.java

@ -37,6 +37,13 @@
<type>sonar-plugin</type> <type>sonar-plugin</type>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.sonarsource.html</groupId>
<artifactId>sonar-html-plugin</artifactId>
<version>${sonar.html.version}</version>
<!--<type>sonar-plugin</type>-->
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.sonarsource.analyzer-commons</groupId> <groupId>org.sonarsource.analyzer-commons</groupId>
@ -86,6 +93,11 @@
<artifactId>junit-jupiter-migrationsupport</artifactId> <artifactId>junit-jupiter-migrationsupport</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.sonarsource.sonarqube</groupId>
<artifactId>sonar-plugin-api-impl</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -101,7 +113,7 @@
<sonarLintSupported>true</sonarLintSupported> <sonarLintSupported>true</sonarLintSupported>
<skipDependenciesPackaging>true</skipDependenciesPackaging> <skipDependenciesPackaging>true</skipDependenciesPackaging>
<sonarQubeMinVersion>8.9</sonarQubeMinVersion> <sonarQubeMinVersion>8.9</sonarQubeMinVersion>
<requirePlugins>java:${sonar.java.version}</requirePlugins> <requirePlugins>java:${sonar.java.version},web:${sonar.html.version}</requirePlugins>
<jreMinVersion>11</jreMinVersion> <jreMinVersion>11</jreMinVersion>
</configuration> </configuration>
</plugin> </plugin>

@ -7,7 +7,9 @@
package com.keyware.sonar.java; package com.keyware.sonar.java;
import com.keyware.sonar.java.rules.JavaSecurityDesignRulesRepository; import com.keyware.sonar.java.rules.JavaSecurityDesignRulesRepository;
import com.keyware.sonar.java.rules.RulesList;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.plugins.html.api.HtmlConstants;
import org.sonarsource.api.sonarlint.SonarLintSide; import org.sonarsource.api.sonarlint.SonarLintSide;
/** /**
@ -21,11 +23,12 @@ public class JavaSecurityDesignWayProfile implements BuiltInQualityProfilesDefin
@Override @Override
public void define(Context context) { public void define(Context context) {
var way = context.createBuiltInQualityProfile("Java信息安全性设计准则", "java"); var javaWay = context.createBuiltInQualityProfile("Java信息安全性设计准则", "java");
way.activateRule(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, "ABCVarNameChecker"); RulesList.getJavaRules().forEach(check -> javaWay.activateRule(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, check.getSimpleName()));
way.activateRule(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, "AbsolutePathDetectorChecker"); javaWay.done();
way.activateRule(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, "DynamicCodeChecker");
way.activateRule(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, "DynamicLibraryLoadChecker"); var webWay = context.createBuiltInQualityProfile("Web信息安全性设计准则", HtmlConstants.LANGUAGE_KEY);
way.done(); RulesList.getHtmlRules().forEach(check -> webWay.activateRule(JavaSecurityDesignRulesRepository.REPOSITORY_KEY + "-" + HtmlConstants.LANGUAGE_KEY, check.getSimpleName()));
webWay.done();
} }
} }

@ -6,11 +6,11 @@
*/ */
package com.keyware.sonar.java.rules; package com.keyware.sonar.java.rules;
import org.sonar.plugins.html.api.HtmlConstants;
import org.sonar.plugins.java.api.CheckRegistrar; import org.sonar.plugins.java.api.CheckRegistrar;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonarsource.api.sonarlint.SonarLintSide; import org.sonarsource.api.sonarlint.SonarLintSide;
import java.util.List; import java.util.Collections;
/** /**
* 负责将java规则检查器注册到SonarQube中 * 负责将java规则检查器注册到SonarQube中
@ -26,20 +26,8 @@ public class JavaFileCheckRegistrar implements CheckRegistrar {
@Override @Override
public void register(RegistrarContext registrarContext) { public void register(RegistrarContext registrarContext) {
// 调用 registerClassesForRepository 以将类与正确的存储库密钥相关联 // 调用 registerClassesForRepository 以将类与正确的存储库密钥相关联
registrarContext.registerClassesForRepository(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, checkClasses(), testCheckClasses()); registrarContext.registerClassesForRepository(JavaSecurityDesignRulesRepository.REPOSITORY_KEY, RulesList.getJavaRules(), Collections.emptyList());
registrarContext.registerClassesForRepository(JavaSecurityDesignRulesRepository.REPOSITORY_KEY + "-" + HtmlConstants.LANGUAGE_KEY, RulesList.getHtmlRules(), Collections.emptyList());
} }
/**
* 列出插件提供的所有主检查器
*/
public static List<Class<? extends JavaCheck>> checkClasses() {
return RulesList.getJavaChecks();
}
/**
* 列出插件提供的所有测试检查器
*/
public static List<Class<? extends JavaCheck>> testCheckClasses() {
return RulesList.getJavaTestChecks();
}
} }

@ -12,6 +12,7 @@ import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime; import org.sonar.api.SonarRuntime;
import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.Version; import org.sonar.api.utils.Version;
import org.sonar.plugins.html.api.HtmlConstants;
import org.sonarsource.analyzer.commons.RuleMetadataLoader; import org.sonarsource.analyzer.commons.RuleMetadataLoader;
import java.util.ArrayList; import java.util.ArrayList;
@ -43,15 +44,16 @@ public class JavaSecurityDesignRulesRepository implements RulesDefinition {
@Override @Override
public void define(RulesDefinition.Context context) { public void define(RulesDefinition.Context context) {
RulesDefinition.NewRepository repository = context.createRepository(REPOSITORY_KEY, "java").setName(REPOSITORY_NAME); RulesDefinition.NewRepository javaRepo = context.createRepository(REPOSITORY_KEY, "java").setName(REPOSITORY_NAME);
RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH, runtime); RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH, runtime);
ruleMetadataLoader.addRulesByAnnotatedClass(javaRepo, new ArrayList<>(RulesList.getJavaRules()));
ruleMetadataLoader.addRulesByAnnotatedClass(repository, new ArrayList<>(RulesList.getChecks())); setTemplates(javaRepo);
javaRepo.done();
setTemplates(repository);
RulesDefinition.NewRepository htmlRepo = context.createRepository(REPOSITORY_KEY + "-" + HtmlConstants.LANGUAGE_KEY, HtmlConstants.LANGUAGE_KEY).setName(REPOSITORY_NAME);
repository.done(); ruleMetadataLoader.addRulesByAnnotatedClass(htmlRepo, new ArrayList<>(RulesList.getHtmlRules()));
setTemplates(htmlRepo);
htmlRepo.done();
} }
private static void setTemplates(RulesDefinition.NewRepository repository) { private static void setTemplates(RulesDefinition.NewRepository repository) {

@ -9,43 +9,39 @@ package com.keyware.sonar.java.rules;
import com.keyware.sonar.java.rules.checkers.*; import com.keyware.sonar.java.rules.checkers.*;
import org.sonar.plugins.java.api.JavaCheck; import org.sonar.plugins.java.api.JavaCheck;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public final class RulesList { public final class RulesList {
private RulesList() {
}
public static List<Class<? extends JavaCheck>> getChecks() {
List<Class<? extends JavaCheck>> checks = new ArrayList<>();
checks.addAll(getJavaChecks());
checks.addAll(getJavaTestChecks());
return Collections.unmodifiableList(checks);
}
/** /**
* These rules are going to target MAIN code only * These rules are going to target MAIN code only
*/ */
public static List<Class<? extends JavaCheck>> getJavaChecks() { public static List<Class<? extends JavaCheck>> getJavaRules() {
return List.of( return List.of(
ABCVarNameChecker.class, //ABCVarNameChecker.class,
AbsolutePathDetectorChecker.class, AbsolutePathDetectorChecker.class,
PathAndKeywordCheck.class, AvoidSensitiveInfoInLogsCheck.class,
CookieSensitiveParameterCheck.class,
DynamicCodeChecker.class, DynamicCodeChecker.class,
DynamicLibraryLoadChecker.class,
FileCheck.class,
HashSaltPassWordChecker.class,
HttpInputDataChecker.class,
InputSQLVerifyChecker.class,
Md5PassWordVerifyChecker.class,
PasswordRegexCheck.class,
PathAndKeywordCheck.class,
RedirectUrlChecker.class,
RSAEncryptionChecker.class,
SecurityCookieChecker.class,
SystemFunctionChecker.class, SystemFunctionChecker.class,
UploadFileVerifyChecker.class, UploadFileVerifyChecker.class,
SecurityCookieChecker.class, UpperCycleLimitRuleChecker.class
RedirectUrlChecker.class,
DynamicLibraryLoadChecker.class
); );
} }
public static List<Class<? extends JavaCheck>> getHtmlRules() {
/** return List.of(
* These rules are going to target TEST code only PasswordInputTagChecker.class
*/ );
public static List<Class<? extends JavaCheck>> getJavaTestChecks() {
return Collections.emptyList();
} }
} }

@ -0,0 +1,38 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称信息安全性设计准则检查插件
* 项目描述用于检查源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.rules.checkers;
import org.sonar.check.Rule;
import org.sonar.plugins.html.checks.AbstractPageCheck;
import org.sonar.plugins.html.node.TagNode;
import org.sonar.plugins.java.api.JavaCheck;
/**
* <p>规则用户输入口令时应对口令域进行掩饰用户输入的每一个字符都应该以星号形式回显</p>
* 验证逻辑当input标签的name或者id包含password时如果type不是password时则报告问题
*
* @author GuoXin
* @date 2024/1/20
*/
@Rule(key = "PasswordInputTagChecker")
public class PasswordInputTagChecker extends AbstractPageCheck implements JavaCheck {
@Override
public void startElement(TagNode node) {
if ("input".equalsIgnoreCase(node.getNodeName())) {
var id = node.getAttribute("id");
var name = node.getAttribute("name");
var type = node.getAttribute("type");
// 当name或者id包含password时,如果type不是password时,则报告问题
if ((id != null && id.contains("password")) || (name != null && name.contains("password"))) {
if (!"password".equalsIgnoreCase(type)) {
createViolation(node, "密码输入框的type属性不为password");
}
}
}
}
}

@ -38,7 +38,7 @@ public class RedirectUrlChecker extends IssuableSubscriptionVisitor {
// 判断方法的返回节点的类型为RedirectView 或 String 类型 // 判断方法的返回节点的类型为RedirectView 或 String 类型
if ("RedirectView".equals(methodTree.returnType().toString())) { if ("RedirectView".equals(methodTree.returnType().toString())) {
// 传递上下文,和方法的参数列表 // 传递上下文,和方法的参数列表
new RedirectViewCheckVisitor(this, parameters).check(block); block.accept(new RedirectViewCheckVisitor(this, parameters));
} else if ("String".equals(methodTree.returnType().toString())) { } else if ("String".equals(methodTree.returnType().toString())) {
checkByStringType(block, parameters); checkByStringType(block, parameters);
} }
@ -110,7 +110,7 @@ public class RedirectUrlChecker extends IssuableSubscriptionVisitor {
} }
static class RedirectViewCheckVisitor extends IssuableSubscriptionVisitor { static class RedirectViewCheckVisitor extends BaseTreeVisitor {
private final RedirectUrlChecker checker; private final RedirectUrlChecker checker;
// 方法的参数列表 // 方法的参数列表
private final List<? extends VariableTree> methodParameters; private final List<? extends VariableTree> methodParameters;
@ -120,40 +120,28 @@ public class RedirectUrlChecker extends IssuableSubscriptionVisitor {
this.methodParameters = parameters; this.methodParameters = parameters;
} }
public void check(Tree block) {
this.scanTree(block);
}
@Override @Override
public List<Tree.Kind> nodesToVisit() { public void visitNewClass(NewClassTree classTree) {
// 订阅new class和 函数调用的节点 // 判断是否为RedirectView,如果是,则判断是否有参数,如果有参数,则判断参数的类型是否由方法传递进来的
var nodeType = new Tree.Kind[]{Tree.Kind.NEW_CLASS, Tree.Kind.METHOD_INVOCATION}; String name = classTree.identifier().toString();
return Arrays.asList(nodeType); if ("RedirectView".equals(name)) {
if (classTree.arguments().size() > 0) {
// 获取第一个参数语法树节点
ExpressionTree argNode = classTree.arguments().get(0);
checkArgs(argNode, classTree);
}
}
} }
@Override @Override
public void visitNode(Tree tree) { public void visitMethodInvocation(MethodInvocationTree invocationTree) {
if (tree.is(Tree.Kind.NEW_CLASS)) { ExpressionTree expressionTree = invocationTree.methodSelect();
NewClassTree classTree = (NewClassTree) tree; if (expressionTree instanceof MemberSelectExpressionTree) {
// 判断是否为RedirectView,如果是,则判断是否有参数,如果有参数,则判断参数的类型是否由方法传递进来的 MemberSelectExpressionTree member = (MemberSelectExpressionTree) expressionTree;
String name = classTree.identifier().toString(); if (member.expression().symbolType().is("RedirectView")
if ("RedirectView".equals(name)) { && "setUrl".equals(member.identifier().name())) {
if (classTree.arguments().size() > 0) { ExpressionTree argNode = invocationTree.arguments().get(0);
// 获取第一个参数语法树节点 checkArgs(argNode, invocationTree);
ExpressionTree argNode = classTree.arguments().get(0);
checkArgs(argNode, tree);
}
}
} else {
MethodInvocationTree invocationTree = (MethodInvocationTree) tree;
ExpressionTree expressionTree = invocationTree.methodSelect();
if (expressionTree instanceof MemberSelectExpressionTree) {
MemberSelectExpressionTree member = (MemberSelectExpressionTree) expressionTree;
if (member.expression().symbolType().is("RedirectView")
&& "setUrl".equals(member.identifier().name())) {
ExpressionTree argNode = invocationTree.arguments().get(0);
checkArgs(argNode, tree);
}
} }
} }
} }

@ -20,7 +20,7 @@ import java.util.List;
* @date 2024/1/8 * @date 2024/1/8
*/ */
@Rule(key = "UploadFileVerify") @Rule(key = "UploadFileVerifyChecker")
public class UploadFileVerifyChecker extends IssuableSubscriptionVisitor { public class UploadFileVerifyChecker extends IssuableSubscriptionVisitor {
private final String value = "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"; private final String value = "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型";

@ -0,0 +1,9 @@
<h2>用户输入口令时应对口令域进行掩饰,用户输入的每一个字符都应该以星号形式回显。</h2>
<p>用户输入口令时应对口令域进行掩饰,用户输入的每一个字符都应该以星号形式回显。</p>
<pre>
</pre>
<h2>合规解决方案</h2>
<pre>
</pre>

@ -0,0 +1,13 @@
{
"title": "用户输入口令时应对口令域进行掩饰。用户输入的每一个字符都应该以星号形式回显",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "15min"
},
"tags": [
"28suo"
],
"defaultSeverity": "Major"
}

@ -0,0 +1,14 @@
<html>
<head><title>Test for PasswordInputTagChecker</title></head>
<body>
<h1>Test for PasswordInputTagChecker</h1>
<h2>Test 1 - FAIL</h2>
<p>
<form action="test.html" method="post">
<input type="password" name="password" value=""/>
<input type="text" name="password" value=""/>
<input type="submit" value="Submit"/>
</form>
</p>
</body>
</html>

@ -27,7 +27,7 @@ public class JavaFileCheckRegistrarTest {
JavaFileCheckRegistrar registrar = new JavaFileCheckRegistrar(); JavaFileCheckRegistrar registrar = new JavaFileCheckRegistrar();
registrar.register(context); registrar.register(context);
assertThat(context.checkClasses()).hasSize(9); assertThat(context.checkClasses()).hasSize(1);
assertThat(context.testCheckClasses()).hasSize(0); assertThat(context.testCheckClasses()).hasSize(0);
} }

@ -7,9 +7,6 @@
package com.keyware.sonar.java.rules; package com.keyware.sonar.java.rules;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinition;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -31,7 +28,7 @@ public class JavaSecurityDesignRulesRepositoryTest {
assertThat(repository.name()).isEqualTo(JavaSecurityDesignRulesRepository.REPOSITORY_NAME); assertThat(repository.name()).isEqualTo(JavaSecurityDesignRulesRepository.REPOSITORY_NAME);
assertThat(repository.language()).isEqualTo("java"); assertThat(repository.language()).isEqualTo("java");
assertThat(repository.rules()).hasSize(RulesList.getChecks().size()); assertThat(repository.rules()).hasSize(RulesList.getJavaRules().size());
assertThat(repository.rules().stream().filter(RulesDefinition.Rule::template)).isEmpty(); assertThat(repository.rules().stream().filter(RulesDefinition.Rule::template)).isEmpty();
} }

@ -0,0 +1,35 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称信息安全性设计准则检查插件
* 项目描述用于检查源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.rules.checkers;
import com.keyware.sonar.java.utils.HtmlCheckMessagesVerifierRule;
import com.keyware.sonar.java.utils.HtmlTestHelper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.sonar.plugins.html.visitor.HtmlSourceCode;
import java.io.File;
/**
* 测试规则用户输入口令时应对口令域进行掩饰用户输入的每一个字符都应该以星号形式回显
*
* @author GuoXin
* @date 2024/1/20
*/
public class PasswordInputTagCheckerTest {
@RegisterExtension
public HtmlCheckMessagesVerifierRule checkMessagesVerifier = new HtmlCheckMessagesVerifierRule();
@Test
public void detected() throws Exception {
HtmlSourceCode sourceCode = HtmlTestHelper.scan(new File("src/test/files/PasswordInputTagChecker.html"), new PasswordInputTagChecker());
checkMessagesVerifier.verify(sourceCode.getIssues())
.next().atLine(16);
}
}

@ -0,0 +1,113 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称信息安全性设计准则检查插件
* 项目描述用于检查源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.utils;
import org.sonar.plugins.html.checks.HtmlIssue;
import org.sonar.plugins.html.checks.PreciseHtmlIssue;
import javax.annotation.Nullable;
import java.util.*;
/**
* Html检查消息验证器
*
* @author GuoXin
* @date 2024/1/20
*/
public final class HtmlCheckMessagesVerifier {
public static HtmlCheckMessagesVerifier verify(Collection<HtmlIssue> messages) {
return new HtmlCheckMessagesVerifier(messages);
}
private final Iterator<HtmlIssue> iterator;
private HtmlIssue current;
private static final Comparator<HtmlIssue> ORDERING = (left, right) -> {
if (Objects.equals(left.line(), right.line())) {
return left.message().compareTo(right.message());
} else if (left.line() == null) {
return -1;
} else if (right.line() == null) {
return 1;
} else {
return left.line().compareTo(right.line());
}
};
private HtmlCheckMessagesVerifier(Collection<HtmlIssue> messages) {
ArrayList<HtmlIssue> messagesList = new ArrayList<>(messages);
messagesList.sort(ORDERING);
iterator = messagesList.iterator();
}
public HtmlCheckMessagesVerifier next() {
if (!iterator.hasNext()) {
throw new AssertionError("\nExpected violation");
}
current = iterator.next();
return this;
}
public void noMore() {
if (iterator.hasNext()) {
HtmlIssue next = iterator.next();
throw new AssertionError("\nNo more violations expected\ngot: at line " + next.line());
}
}
private void checkStateOfCurrent() {
if (current == null) {
throw new IllegalStateException("Prior to this method you should call next()");
}
}
public HtmlCheckMessagesVerifier atLine(@Nullable Integer expectedLine) {
checkStateOfCurrent();
if (!Objects.equals(expectedLine, current.line())) {
throw new AssertionError("\nExpected: " + expectedLine + "\ngot: " + current.line());
}
return this;
}
public HtmlCheckMessagesVerifier atLocation(int startLine, int startColumn, int endLine, int endColumn) {
checkStateOfCurrent();
PreciseHtmlIssue preciseHtmlIssue = (PreciseHtmlIssue) current;
if (!Objects.equals(startLine, current.line())) {
throw new AssertionError("\nExpected: " + startLine + "\ngot: " + current.line());
}
if (!Objects.equals(startColumn, preciseHtmlIssue.startColumn())) {
throw new AssertionError("\nExpected: " + startColumn + "\ngot: " + preciseHtmlIssue.startColumn());
}
if (!Objects.equals(endLine, preciseHtmlIssue.endLine())) {
throw new AssertionError("\nExpected: " + endLine + "\ngot: " + preciseHtmlIssue.endLine());
}
if (!Objects.equals(endColumn, preciseHtmlIssue.endColumn())) {
throw new AssertionError("\nExpected: " + endColumn + "\ngot: " + preciseHtmlIssue.endColumn());
}
return this;
}
public HtmlCheckMessagesVerifier withMessage(String expectedMessage) {
checkStateOfCurrent();
String actual = current.message();
if (!actual.equals(expectedMessage)) {
throw new AssertionError("\nExpected: \"" + expectedMessage + "\"\ngot: \"" + actual + "\"");
}
return this;
}
public HtmlCheckMessagesVerifier withCost(@Nullable Double expectedCost) {
checkStateOfCurrent();
if (!Objects.equals(expectedCost, current.cost())) {
throw new AssertionError("\nExpected: " + expectedCost + "\ngot: " + current.cost());
}
return this;
}
}

@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称信息安全性设计准则检查插件
* 项目描述用于检查源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.utils;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.sonar.plugins.html.checks.HtmlIssue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Html规则校验
*
* @author GuoXin
* @date 2024/1/20
*/
public class HtmlCheckMessagesVerifierRule implements AfterEachCallback {
private final List<HtmlCheckMessagesVerifier> verifiers = new ArrayList<>();
public HtmlCheckMessagesVerifier verify(Collection<HtmlIssue> messages) {
HtmlCheckMessagesVerifier verifier = HtmlCheckMessagesVerifier.verify(messages);
verifiers.add(verifier);
return verifier;
}
protected void verify() {
for (HtmlCheckMessagesVerifier verifier : verifiers) {
verifier.noMore();
}
}
@Override
public void afterEach(ExtensionContext extensionContext) throws Exception {
verify();
}
}

@ -0,0 +1,66 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称信息安全性设计准则检查插件
* 项目描述用于检查源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.utils;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.plugins.html.analyzers.ComplexityVisitor;
import org.sonar.plugins.html.analyzers.PageCountLines;
import org.sonar.plugins.html.api.HtmlConstants;
import org.sonar.plugins.html.lex.PageLexer;
import org.sonar.plugins.html.lex.VueLexer;
import org.sonar.plugins.html.visitor.DefaultNodeVisitor;
import org.sonar.plugins.html.visitor.HtmlAstScanner;
import org.sonar.plugins.html.visitor.HtmlSourceCode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* Html测试工具类
*
* @author GuoXin
* @date 2024/1/20
*/
public class HtmlTestHelper {
private HtmlTestHelper() {
}
public static HtmlSourceCode scan(File file, DefaultNodeVisitor visitor) {
FileReader fileReader;
try {
fileReader = new FileReader(file);
} catch (FileNotFoundException e) {
throw new IllegalStateException(e);
}
HtmlSourceCode result = new HtmlSourceCode(
new TestInputFileBuilder("key", file.getPath())
.setLanguage(HtmlConstants.LANGUAGE_KEY)
.setType(InputFile.Type.MAIN)
.setModuleBaseDir(new File(".").toPath())
.setCharset(StandardCharsets.UTF_8)
.build()
);
HtmlAstScanner walker = new HtmlAstScanner(List.of(new PageCountLines(), new ComplexityVisitor()));
PageLexer lexer = file.getName().endsWith(".vue") ? new VueLexer() : new PageLexer();
walker.addVisitor(visitor);
walker.scan(
lexer.parse(fileReader),
result
);
return result;
}
}
Loading…
Cancel
Save