parent
92c262561a
commit
be9b9f2dfb
@ -0,0 +1,66 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.java; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import org.sonar.api.config.Configuration; |
||||||
|
import org.sonar.api.resources.AbstractLanguage; |
||||||
|
|
||||||
|
/** |
||||||
|
* Java language implementation |
||||||
|
* |
||||||
|
* @since 1.3 |
||||||
|
*/ |
||||||
|
public class Java extends AbstractLanguage { |
||||||
|
|
||||||
|
/** |
||||||
|
* Java key |
||||||
|
*/ |
||||||
|
public static final String KEY = "java"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Java name |
||||||
|
*/ |
||||||
|
public static final String NAME = "Java"; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Key of the file suffix parameter |
||||||
|
*/ |
||||||
|
public static final String FILE_SUFFIXES_KEY = "sonar.java.file.suffixes"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Default Java fil |
||||||
|
* es knows suffixes |
||||||
|
*/ |
||||||
|
public static final String DEFAULT_FILE_SUFFIXES = ".java,.jav"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Settings of the plugin. |
||||||
|
*/ |
||||||
|
private final Configuration settings; |
||||||
|
|
||||||
|
/** |
||||||
|
* Default constructor |
||||||
|
*/ |
||||||
|
public Java(Configuration settings) { |
||||||
|
super(KEY, NAME); |
||||||
|
this.settings = settings; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* @see org.sonar.api.resources.AbstractLanguage#getFileSuffixes() |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String[] getFileSuffixes() { |
||||||
|
String[] suffixes = Arrays.stream(settings.getStringArray(Java.FILE_SUFFIXES_KEY)).filter(s -> s != null && !s.trim().isEmpty()).toArray(String[]::new); |
||||||
|
return suffixes.length > 0 ? suffixes : DEFAULT_FILE_SUFFIXES.split(","); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,200 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.java; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.util.*; |
||||||
|
import java.util.function.UnaryOperator; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
import javax.annotation.Nullable; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.sonar.api.batch.Phase; |
||||||
|
import org.sonar.api.batch.fs.FileSystem; |
||||||
|
import org.sonar.api.batch.fs.InputFile; |
||||||
|
import org.sonar.api.batch.sensor.Sensor; |
||||||
|
import org.sonar.api.batch.sensor.SensorContext; |
||||||
|
import org.sonar.api.batch.sensor.SensorDescriptor; |
||||||
|
import org.sonar.api.config.Configuration; |
||||||
|
import org.sonar.api.issue.NoSonarFilter; |
||||||
|
import org.sonar.api.rule.RuleKey; |
||||||
|
import org.sonar.api.scan.issue.filter.FilterableIssue; |
||||||
|
import org.sonar.api.scan.issue.filter.IssueFilterChain; |
||||||
|
import org.sonar.java.JavaFrontend; |
||||||
|
import org.sonar.java.Measurer; |
||||||
|
import org.sonar.java.SonarComponents; |
||||||
|
import org.sonar.java.annotations.VisibleForTesting; |
||||||
|
import org.sonar.java.checks.CheckList; |
||||||
|
import org.sonar.java.filters.PostAnalysisIssueFilter; |
||||||
|
import org.sonar.java.jsp.Jasper; |
||||||
|
import org.sonar.java.model.GeneratedFile; |
||||||
|
import org.sonar.java.model.JavaVersionImpl; |
||||||
|
import org.sonar.java.se.SymbolicExecutionVisitor; |
||||||
|
import org.sonar.java.se.checks.SECheck; |
||||||
|
import org.sonar.plugins.java.api.JavaCheck; |
||||||
|
import org.sonar.plugins.java.api.JavaResourceLocator; |
||||||
|
import org.sonar.plugins.java.api.JavaVersion; |
||||||
|
import org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader; |
||||||
|
import org.sonarsource.performance.measure.PerformanceMeasure; |
||||||
|
|
||||||
|
import static org.sonar.api.rules.RuleAnnotationUtils.getRuleKey; |
||||||
|
|
||||||
|
|
||||||
|
@Phase(name = Phase.Name.PRE) |
||||||
|
public class KeyJavaSensor implements Sensor{ |
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(KeyJavaSensor.class); |
||||||
|
|
||||||
|
private static final String PERFORMANCE_MEASURE_ACTIVATION_PROPERTY = "sonar.java.performance.measure"; |
||||||
|
private static final String PERFORMANCE_MEASURE_FILE_PATH_PROPERTY = "sonar.java.performance.measure.path"; |
||||||
|
private static final String PERFORMANCE_MEASURE_DESTINATION_FILE = "sonar.java.performance.measure.json"; |
||||||
|
static final String SONAR_WAY_PATH = "/org/sonar/l10n/java/rules/java/Sonar_way_profile.json"; |
||||||
|
private final SonarComponents sonarComponents; |
||||||
|
private final FileSystem fs; |
||||||
|
private final JavaResourceLocator javaResourceLocator; |
||||||
|
private final Configuration settings; |
||||||
|
private final NoSonarFilter noSonarFilter; |
||||||
|
@Nullable |
||||||
|
private final Jasper jasper; |
||||||
|
private final PostAnalysisIssueFilter postAnalysisIssueFilter; |
||||||
|
|
||||||
|
public KeyJavaSensor(SonarComponents sonarComponents, FileSystem fs, |
||||||
|
JavaResourceLocator javaResourceLocator, Configuration settings, |
||||||
|
NoSonarFilter noSonarFilter, |
||||||
|
PostAnalysisIssueFilter postAnalysisIssueFilter, @Nullable Jasper jasper) { |
||||||
|
|
||||||
|
this.noSonarFilter = noSonarFilter; |
||||||
|
this.sonarComponents = sonarComponents; |
||||||
|
this.fs = fs; |
||||||
|
this.javaResourceLocator = javaResourceLocator; |
||||||
|
this.settings = settings; |
||||||
|
this.postAnalysisIssueFilter = postAnalysisIssueFilter; |
||||||
|
this.jasper = jasper; |
||||||
|
this.sonarComponents.registerMainCheckClasses(CheckList.REPOSITORY_KEY, CheckList.getJavaChecks()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void describe(SensorDescriptor descriptor) { |
||||||
|
descriptor.onlyOnLanguage(Java.KEY).name("KeyJavaSensor"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void execute(SensorContext context) { |
||||||
|
PerformanceMeasure.Duration sensorDuration = createPerformanceMeasureReport(context); |
||||||
|
|
||||||
|
sonarComponents.setSensorContext(context); |
||||||
|
|
||||||
|
sonarComponents.setCheckFilter(createCheckFilter(sonarComponents.isAutoScanCheckFiltering())); |
||||||
|
|
||||||
|
Measurer measurer = new Measurer(context, noSonarFilter); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
JavaFrontend frontend = new JavaFrontend(getJavaVersion(), sonarComponents, measurer, javaResourceLocator, postAnalysisIssueFilter, |
||||||
|
insertSymbolicExecutionVisitor(sonarComponents.mainChecks())); |
||||||
|
frontend.scan(getSourceFiles(), getTestFiles(), runJasper(context)); |
||||||
|
|
||||||
|
sensorDuration.stop(); |
||||||
|
} |
||||||
|
|
||||||
|
private UnaryOperator<List<JavaCheck>> createCheckFilter(boolean isAutoScanCheckFiltering) { |
||||||
|
if (isAutoScanCheckFiltering) { |
||||||
|
Set<RuleKey> autoScanCompatibleRules = new HashSet<>(KeyJavaSensor.sonarJavaSonarWayRuleKeys()); |
||||||
|
|
||||||
|
CheckList.getJavaChecksNotWorkingForAutoScan().stream() |
||||||
|
.map(checkClass -> RuleKey.of(CheckList.REPOSITORY_KEY, getRuleKey(checkClass))) |
||||||
|
.forEach(autoScanCompatibleRules::remove); |
||||||
|
|
||||||
|
|
||||||
|
return checks -> checks.stream() |
||||||
|
.filter(check -> sonarComponents.getRuleKey(check).map(autoScanCompatibleRules::contains).orElse(false)) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
} else { |
||||||
|
return UnaryOperator.identity(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static Set<RuleKey> sonarJavaSonarWayRuleKeys() { |
||||||
|
return BuiltInQualityProfileJsonLoader.loadActiveKeysFromJsonProfile(SONAR_WAY_PATH).stream() |
||||||
|
.map(rule -> RuleKey.of(CheckList.REPOSITORY_KEY, rule)) |
||||||
|
.collect(Collectors.toSet()); |
||||||
|
} |
||||||
|
|
||||||
|
private static PerformanceMeasure.Duration createPerformanceMeasureReport(SensorContext context) { |
||||||
|
return PerformanceMeasure.reportBuilder() |
||||||
|
.activate(context.config().get(PERFORMANCE_MEASURE_ACTIVATION_PROPERTY).filter("true"::equals).isPresent()) |
||||||
|
.toFile(context.config().get(PERFORMANCE_MEASURE_FILE_PATH_PROPERTY) |
||||||
|
.filter(path -> !path.isEmpty()) |
||||||
|
.orElseGet(() -> Optional.ofNullable(context.fileSystem().workDir()) |
||||||
|
.filter(File::exists) |
||||||
|
.map(file -> file.toPath().resolve(PERFORMANCE_MEASURE_DESTINATION_FILE).toString()) |
||||||
|
.orElse(null))) |
||||||
|
.appendMeasurementCost() |
||||||
|
.start("KeyJavaSensor"); |
||||||
|
} |
||||||
|
|
||||||
|
@VisibleForTesting |
||||||
|
static JavaCheck[] insertSymbolicExecutionVisitor(List<JavaCheck> checks) { |
||||||
|
List<SECheck> seChecks = checks.stream() |
||||||
|
.filter(SECheck.class::isInstance) |
||||||
|
.map(SECheck.class::cast) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
if (seChecks.isEmpty()) { |
||||||
|
LOG.info("No rules with 'symbolic-execution' tag were enabled," |
||||||
|
+ " the Symbolic Execution Engine will not run during the analysis."); |
||||||
|
return checks.toArray(new JavaCheck[0]); |
||||||
|
} |
||||||
|
List<JavaCheck> newList = new ArrayList<>(checks); |
||||||
|
// insert an instance of SymbolicExecutionVisitor before the first SECheck
|
||||||
|
newList.add(newList.indexOf(seChecks.get(0)), new SymbolicExecutionVisitor(seChecks)); |
||||||
|
return newList.toArray(new JavaCheck[0]); |
||||||
|
} |
||||||
|
|
||||||
|
private Collection<GeneratedFile> runJasper(SensorContext context) { |
||||||
|
if (sonarComponents.isAutoScan()) { |
||||||
|
// for security reasons, do not run jasper to generate code in autoscan mode
|
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return jasper != null ? jasper.generateFiles(context, sonarComponents.getJavaClasspath()) : Collections.emptyList(); |
||||||
|
} |
||||||
|
|
||||||
|
private Iterable<InputFile> getSourceFiles() { |
||||||
|
return javaFiles(InputFile.Type.MAIN); |
||||||
|
} |
||||||
|
|
||||||
|
private Iterable<InputFile> getTestFiles() { |
||||||
|
return javaFiles(InputFile.Type.TEST); |
||||||
|
} |
||||||
|
|
||||||
|
private Iterable<InputFile> javaFiles(InputFile.Type type) { |
||||||
|
return fs.inputFiles(fs.predicates().and(fs.predicates().hasLanguage(Java.KEY), fs.predicates().hasType(type))); |
||||||
|
} |
||||||
|
|
||||||
|
private JavaVersion getJavaVersion() { |
||||||
|
Optional<String> javaVersionAsString = settings.get(JavaVersion.SOURCE_VERSION); |
||||||
|
if (!javaVersionAsString.isPresent()) { |
||||||
|
return new JavaVersionImpl(); |
||||||
|
} |
||||||
|
String enablePreviewAsString = settings.get(JavaVersion.ENABLE_PREVIEW).orElse("false"); |
||||||
|
|
||||||
|
JavaVersion javaVersion = JavaVersionImpl.fromStrings(javaVersionAsString.get(), enablePreviewAsString); |
||||||
|
if (javaVersion.arePreviewFeaturesEnabled() && javaVersion.asInt() < JavaVersionImpl.MAX_SUPPORTED) { |
||||||
|
LOG.warn("sonar.java.enablePreview is set but will be discarded as the Java version is less than the max" + |
||||||
|
" supported version ({} < {})", javaVersion.asInt(), JavaVersionImpl.MAX_SUPPORTED); |
||||||
|
javaVersion = new JavaVersionImpl(javaVersion.asInt(), false); |
||||||
|
} |
||||||
|
LOG.info("Configured Java source version ({}): {}, preview features enabled ({}): {}", |
||||||
|
JavaVersion.SOURCE_VERSION, javaVersion.asInt(), JavaVersion.ENABLE_PREVIEW, javaVersion.arePreviewFeaturesEnabled()); |
||||||
|
return javaVersion; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getClass().getSimpleName(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
{ |
||||||
|
"name": "Sonar way", |
||||||
|
"ruleKeys": [ |
||||||
|
"ABCVarNameChecker", |
||||||
|
"AbsolutePathDetectorChecker", |
||||||
|
"AuthenticationChecker", |
||||||
|
"AvoidSensitiveInfoInLogsCheck", |
||||||
|
"ConfigurationFileChecker", |
||||||
|
"CookieSensitiveParameterCheck", |
||||||
|
"DynamicCodeChecker", |
||||||
|
"DynamicLibraryLoadChecker", |
||||||
|
"ErrorMessageChecker", |
||||||
|
"FileCheck", |
||||||
|
"HashSaltPassWordChecker", |
||||||
|
"HttpInputDataChecker", |
||||||
|
"InputSQLVerifyChecker", |
||||||
|
"Md5PassWordVerifyChecker", |
||||||
|
"OptionsVerifyChecker", |
||||||
|
"PasswordInputTagChecker", |
||||||
|
"PasswordRegexCheck", |
||||||
|
"PathAndKeywordCheck", |
||||||
|
"RedirectUrlChecker", |
||||||
|
"RSAEncryptionChecker", |
||||||
|
"SecurityCookieChecker", |
||||||
|
"SendMessageVerifyChecker", |
||||||
|
"SessionCacheParamsChecker", |
||||||
|
"SessionDateChecker", |
||||||
|
"SystemFunctionChecker", |
||||||
|
"UploadFileVerifyChecker", |
||||||
|
"UpperCycleLimitRuleChecker", |
||||||
|
"UserStatusVerifyChecker" |
||||||
|
] |
||||||
|
} |
Loading…
Reference in new issue