Skip to content

Commit 06e2ee5

Browse files
SONARJAVA-6205 Include DBD and security rules as part of Agentic profile
Refactored to re-use the same code to initialize quality profiles assuming that all DBD and security rules should be part of the new quality profile.
1 parent 35e7ca4 commit 06e2ee5

File tree

5 files changed

+161
-144
lines changed

5 files changed

+161
-144
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* SonarQube Java
3+
* Copyright (C) 2012-2025 SonarSource Sàrl
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the Sonar Source-Available License for more details.
13+
*
14+
* You should have received a copy of the Sonar Source-Available License
15+
* along with this program; if not, see https://sonarsource.com/license/ssal/
16+
*/
17+
package org.sonar.plugins.java;
18+
19+
import java.lang.reflect.InvocationTargetException;
20+
import java.lang.reflect.Method;
21+
import java.util.HashSet;
22+
import java.util.Set;
23+
import java.util.stream.Collectors;
24+
import javax.annotation.Nullable;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
import org.sonar.api.rule.RuleKey;
28+
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
29+
import org.sonar.java.GeneratedCheckList;
30+
import org.sonar.java.annotations.VisibleForTesting;
31+
import org.sonar.plugins.java.api.ProfileRegistrar;
32+
import org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader;
33+
34+
35+
/**
36+
* Defines a Java quality profile including rules from sonar-java, Java SE, DBD and Security.
37+
*/
38+
abstract class BuiltInJavaQualityProfile implements BuiltInQualityProfilesDefinition {
39+
private static final Logger LOG = LoggerFactory.getLogger(BuiltInJavaQualityProfile.class);
40+
41+
static final String SECURITY_RULES_CLASS_NAME = "com.sonar.plugins.security.api.JavaRules";
42+
static final String DBD_RULES_CLASS_NAME = "com.sonarsource.plugins.dbd.api.JavaRules";
43+
static final String SECURITY_RULE_KEYS_METHOD_NAME = "getSecurityRuleKeys";
44+
static final String DBD_RULE_KEYS_METHOD_NAME = "getDataflowBugDetectionRuleKeys";
45+
static final String GET_REPOSITORY_KEY = "getRepositoryKey";
46+
static final String SECURITY_REPOSITORY_KEY = "javasecurity";
47+
static final String DBD_REPOSITORY_KEY = "javabugs";
48+
49+
50+
protected final ProfileRegistrar[] profileRegistrars;
51+
52+
BuiltInJavaQualityProfile(@Nullable ProfileRegistrar[] profileRegistrars) {
53+
this.profileRegistrars = profileRegistrars;
54+
}
55+
56+
abstract String getProfileName();
57+
58+
abstract String getPathToJsonProfile();
59+
60+
abstract boolean isDefault();
61+
62+
@Override
63+
public void define(Context context) {
64+
// Create a new profile
65+
BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile(getProfileName(), Java.KEY);
66+
// Load rules from local JSON
67+
Set<RuleKey> ruleKeys = registerRulesFromJson(getPathToJsonProfile(), profileRegistrars);
68+
69+
// FIXME as part of SONARJAVA-6207
70+
// Former activation mechanism, it should be removed once sonar-security and sonar-dataflow-bug-detection
71+
// support the new mechanism:
72+
// <code> registrarContext.internal().registerDefaultQualityProfileRules(ruleKeys); </code>
73+
// For now, it still uses reflexion if rules are not yet defined
74+
if (ruleKeys.stream().noneMatch(rule -> SECURITY_REPOSITORY_KEY.equals(rule.repository()))) {
75+
ruleKeys.addAll(getSecurityRuleKeys());
76+
}
77+
if (ruleKeys.stream().noneMatch(rule -> DBD_REPOSITORY_KEY.equals(rule.repository()))) {
78+
ruleKeys.addAll(getDataflowBugDetectionRuleKeys());
79+
}
80+
81+
ruleKeys.forEach(ruleKey -> profile.activateRule(ruleKey.repository(), ruleKey.rule()));
82+
profile.setDefault(isDefault());
83+
profile.done();
84+
}
85+
86+
static Set<RuleKey> registerRulesFromJson(String pathToJsonProfile, @Nullable ProfileRegistrar[] profileRegistrars) {
87+
Set<RuleKey> ruleKeys = new HashSet<>(loadRuleKeys(pathToJsonProfile));
88+
if (profileRegistrars != null) {
89+
for (ProfileRegistrar profileRegistrar : profileRegistrars) {
90+
profileRegistrar.register(ruleKeys::addAll);
91+
}
92+
}
93+
94+
return ruleKeys;
95+
}
96+
97+
static Set<RuleKey> loadRuleKeys(final String pathToJsonProfile) {
98+
return BuiltInQualityProfileJsonLoader.loadActiveKeysFromJsonProfile(pathToJsonProfile).stream()
99+
.map(rule -> RuleKey.of(GeneratedCheckList.REPOSITORY_KEY, rule))
100+
.collect(Collectors.toSet());
101+
}
102+
103+
@VisibleForTesting
104+
Set<RuleKey> getSecurityRuleKeys() {
105+
return getExternalRuleKeys(SECURITY_RULES_CLASS_NAME, SECURITY_RULE_KEYS_METHOD_NAME, "security");
106+
}
107+
108+
@VisibleForTesting
109+
Set<RuleKey> getDataflowBugDetectionRuleKeys() {
110+
return getExternalRuleKeys(DBD_RULES_CLASS_NAME, DBD_RULE_KEYS_METHOD_NAME, "dataflow bug detection");
111+
}
112+
113+
@SuppressWarnings("unchecked")
114+
@VisibleForTesting
115+
Set<RuleKey> getExternalRuleKeys(String className, String ruleKeysMethod, String rulesCategory) {
116+
try {
117+
Class<?> javaRulesClass = Class.forName(className);
118+
Method getRuleKeysMethod = javaRulesClass.getMethod(ruleKeysMethod);
119+
Set<String> ruleKeys = (Set<String>) getRuleKeysMethod.invoke(null);
120+
Method getRepositoryKeyMethod = javaRulesClass.getMethod(GET_REPOSITORY_KEY);
121+
String repositoryKey = (String) getRepositoryKeyMethod.invoke(null);
122+
return ruleKeys.stream().map(k -> RuleKey.of(repositoryKey, k)).collect(Collectors.toSet());
123+
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
124+
LOG.debug(String.format("[%s], no %s rules added to %s java profile: %s", e.getClass().getSimpleName(), rulesCategory, getProfileName(), e.getMessage()));
125+
}
126+
return new HashSet<>();
127+
}
128+
}

sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaAgenticWayProfile.java

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,32 @@
1616
*/
1717
package org.sonar.plugins.java;
1818

19-
import java.util.Set;
2019
import javax.annotation.Nullable;
21-
import org.sonar.api.rule.RuleKey;
22-
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
2320
import org.sonar.plugins.java.api.ProfileRegistrar;
2421
import org.sonarsource.api.sonarlint.SonarLintSide;
2522

2623
@SonarLintSide
27-
public class JavaAgenticWayProfile implements BuiltInQualityProfilesDefinition {
28-
private final ProfileRegistrar[] profileRegistrars;
29-
30-
/**
31-
* Constructor used by Pico container (SC) when no ProfileRegistrar are available
32-
*/
24+
public class JavaAgenticWayProfile extends BuiltInJavaQualityProfile {
3325
public JavaAgenticWayProfile() {
3426
this(null);
3527
}
3628

3729
public JavaAgenticWayProfile(@Nullable ProfileRegistrar[] profileRegistrars) {
38-
this.profileRegistrars = profileRegistrars;
30+
super(profileRegistrars);
31+
}
32+
33+
@Override
34+
String getProfileName() {
35+
return "AI Quality Profile";
3936
}
4037

4138
@Override
42-
public void define(Context context) {
43-
NewBuiltInQualityProfile agenticWay = context.createBuiltInQualityProfile("AI Quality Profile", Java.KEY);
44-
Set<RuleKey> ruleKeys = QualityProfileUtils.registerRulesFromJson(
45-
"/org/sonar/l10n/java/rules/java/Agentic_way_profile.json",
46-
this.profileRegistrars
47-
);
39+
String getPathToJsonProfile() {
40+
return "/org/sonar/l10n/java/rules/java/Agentic_way_profile.json";
41+
}
4842

49-
ruleKeys.forEach(ruleKey -> agenticWay.activateRule(ruleKey.repository(), ruleKey.rule()));
50-
agenticWay.done();
43+
@Override
44+
boolean isDefault() {
45+
return false;
5146
}
5247
}

sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaSonarWayProfile.java

Lines changed: 12 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,19 @@
1616
*/
1717
package org.sonar.plugins.java;
1818

19-
import java.lang.reflect.InvocationTargetException;
20-
import java.lang.reflect.Method;
21-
import java.util.HashSet;
2219
import java.util.Set;
23-
import java.util.stream.Collectors;
2420
import javax.annotation.Nullable;
25-
import org.slf4j.Logger;
26-
import org.slf4j.LoggerFactory;
2721
import org.sonar.api.rule.RuleKey;
28-
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
29-
import org.sonar.java.annotations.VisibleForTesting;
3022
import org.sonar.plugins.java.api.ProfileRegistrar;
3123
import org.sonarsource.api.sonarlint.SonarLintSide;
3224

3325
/**
3426
* define built-in profile
3527
*/
3628
@SonarLintSide
37-
public class JavaSonarWayProfile implements BuiltInQualityProfilesDefinition {
38-
39-
private static final Logger LOG = LoggerFactory.getLogger(JavaSonarWayProfile.class);
40-
41-
static final String SECURITY_RULES_CLASS_NAME = "com.sonar.plugins.security.api.JavaRules";
42-
static final String DBD_RULES_CLASS_NAME = "com.sonarsource.plugins.dbd.api.JavaRules";
43-
static final String SECURITY_RULE_KEYS_METHOD_NAME = "getSecurityRuleKeys";
44-
static final String DBD_RULE_KEYS_METHOD_NAME = "getDataflowBugDetectionRuleKeys";
45-
static final String GET_REPOSITORY_KEY = "getRepositoryKey";
46-
static final String SECURITY_REPOSITORY_KEY = "javasecurity";
47-
static final String DBD_REPOSITORY_KEY = "javabugs";
48-
29+
public class JavaSonarWayProfile extends BuiltInJavaQualityProfile {
4930
static final String SONAR_WAY_PATH = "/org/sonar/l10n/java/rules/java/Sonar_way_profile.json";
5031

51-
private final ProfileRegistrar[] profileRegistrars;
52-
5332
/**
5433
* Constructor used by Pico container (SC) when no ProfileRegistrar are available
5534
*/
@@ -58,59 +37,25 @@ public JavaSonarWayProfile() {
5837
}
5938

6039
public JavaSonarWayProfile(@Nullable ProfileRegistrar[] profileRegistrars) {
61-
this.profileRegistrars = profileRegistrars;
40+
super(profileRegistrars);
6241
}
6342

6443
@Override
65-
public void define(Context context) {
66-
NewBuiltInQualityProfile sonarWay = context.createBuiltInQualityProfile("Sonar way", Java.KEY);
67-
Set<RuleKey> ruleKeys = QualityProfileUtils.registerRulesFromJson(
68-
SONAR_WAY_PATH,
69-
this.profileRegistrars
70-
);
71-
72-
// Former activation mechanism, it should be removed once sonar-security and sonar-dataflow-bug-detection
73-
// support the new mechanism:
74-
// <code> registrarContext.internal().registerDefaultQualityProfileRules(ruleKeys); </code>
75-
// For now, it still uses reflexion if rules are not yet defined
76-
if (ruleKeys.stream().noneMatch(rule -> SECURITY_REPOSITORY_KEY.equals(rule.repository()))) {
77-
ruleKeys.addAll(getSecurityRuleKeys());
78-
}
79-
if (ruleKeys.stream().noneMatch(rule -> DBD_REPOSITORY_KEY.equals(rule.repository()))) {
80-
ruleKeys.addAll(getDataflowBugDetectionRuleKeys());
81-
}
82-
83-
ruleKeys.forEach(ruleKey -> sonarWay.activateRule(ruleKey.repository(), ruleKey.rule()));
84-
sonarWay.done();
85-
}
86-
87-
static Set<RuleKey> sonarJavaSonarWayRuleKeys() {
88-
return QualityProfileUtils.loadRuleKeys(SONAR_WAY_PATH);
44+
String getProfileName() {
45+
return "Sonar way";
8946
}
9047

91-
@VisibleForTesting
92-
static Set<RuleKey> getSecurityRuleKeys() {
93-
return getExternalRuleKeys(SECURITY_RULES_CLASS_NAME, SECURITY_RULE_KEYS_METHOD_NAME, "security");
48+
@Override
49+
String getPathToJsonProfile() {
50+
return SONAR_WAY_PATH;
9451
}
9552

96-
@VisibleForTesting
97-
static Set<RuleKey> getDataflowBugDetectionRuleKeys() {
98-
return getExternalRuleKeys(DBD_RULES_CLASS_NAME, DBD_RULE_KEYS_METHOD_NAME, "dataflow bug detection");
53+
@Override
54+
boolean isDefault() {
55+
return true;
9956
}
10057

101-
@SuppressWarnings("unchecked")
102-
@VisibleForTesting
103-
static Set<RuleKey> getExternalRuleKeys(String className, String ruleKeysMethod, String rulesCategory) {
104-
try {
105-
Class<?> javaRulesClass = Class.forName(className);
106-
Method getRuleKeysMethod = javaRulesClass.getMethod(ruleKeysMethod);
107-
Set<String> ruleKeys = (Set<String>) getRuleKeysMethod.invoke(null);
108-
Method getRepositoryKeyMethod = javaRulesClass.getMethod(GET_REPOSITORY_KEY);
109-
String repositoryKey = (String) getRepositoryKeyMethod.invoke(null);
110-
return ruleKeys.stream().map(k -> RuleKey.of(repositoryKey, k)).collect(Collectors.toSet());
111-
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
112-
LOG.debug(String.format("[%s], no %s rules added to Sonar way java profile: %s", e.getClass().getSimpleName(), rulesCategory, e.getMessage()));
113-
}
114-
return new HashSet<>();
58+
public static Set<RuleKey> sonarJavaSonarWayRuleKeys() {
59+
return loadRuleKeys(SONAR_WAY_PATH);
11560
}
11661
}

sonar-java-plugin/src/main/java/org/sonar/plugins/java/QualityProfileUtils.java

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)