You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XooRulesDefinition.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  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 GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.xoo.rule;
  21. import javax.annotation.Nullable;
  22. import org.sonar.api.SonarRuntime;
  23. import org.sonar.api.rule.RuleScope;
  24. import org.sonar.api.rules.RuleType;
  25. import org.sonar.api.server.rule.RuleDescriptionSection;
  26. import org.sonar.api.server.rule.RuleParamType;
  27. import org.sonar.api.server.rule.RulesDefinition;
  28. import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader;
  29. import org.sonar.api.utils.Version;
  30. import org.sonar.xoo.Xoo;
  31. import org.sonar.xoo.Xoo2;
  32. import org.sonar.xoo.checks.Check;
  33. import org.sonar.xoo.rule.hotspot.HotspotWithContextsSensor;
  34. import org.sonar.xoo.rule.hotspot.HotspotWithSingleContextSensor;
  35. import org.sonar.xoo.rule.hotspot.HotspotWithoutContextSensor;
  36. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
  37. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
  38. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.INTRODUCTION_SECTION_KEY;
  39. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY;
  40. import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
  41. import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2017;
  42. import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2021;
  43. /**
  44. * Define all the coding rules that are supported on the repositories named "xoo" and "xoo2"
  45. */
  46. public class XooRulesDefinition implements RulesDefinition {
  47. public static final String[] AVAILABLE_CONTEXTS = {"javascript", "jquery", "express_js", "react", "axios"};
  48. public static final String XOO_REPOSITORY = "xoo";
  49. public static final String XOO2_REPOSITORY = "xoo2";
  50. private static final String TEN_MIN = "10min";
  51. @Nullable
  52. private final Version version;
  53. public XooRulesDefinition() {
  54. this(null);
  55. }
  56. public XooRulesDefinition(@Nullable SonarRuntime sonarRuntime) {
  57. this.version = sonarRuntime != null ? sonarRuntime.getApiVersion() : null;
  58. }
  59. @Override
  60. public void define(Context context) {
  61. defineRulesXoo(context);
  62. defineRulesXoo2(context);
  63. defineRulesXooExternal(context);
  64. }
  65. private static void defineRulesXoo2(Context context) {
  66. NewRepository repo = context.createRepository(XOO2_REPOSITORY, Xoo2.KEY).setName("Xoo2");
  67. NewRule hasTag = repo.createRule(HasTagSensor.RULE_KEY).setName("Has Tag");
  68. addAllDescriptionSections(hasTag, "Search for a given tag in Xoo files");
  69. NewRule oneIssuePerLine = repo.createRule(OneIssuePerLineSensor.RULE_KEY).setName("One Issue Per Line");
  70. addAllDescriptionSections(oneIssuePerLine, "Generate an issue on each line of a file. It requires the metric \"lines\".");
  71. oneIssuePerLine
  72. .setDebtRemediationFunction(hasTag.debtRemediationFunctions().linear("1min"))
  73. .setGapDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code");
  74. repo.done();
  75. }
  76. private void defineRulesXoo(Context context) {
  77. NewRepository repo = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
  78. new RulesDefinitionAnnotationLoader().load(repo, Check.ALL);
  79. NewRule hasTag = repo.createRule(HasTagSensor.RULE_KEY).setName("Has Tag")
  80. .setActivatedByDefault(true)
  81. .addDescriptionSection(howToFixSectionWithContext("single_context"));
  82. addDescriptionSectionsWithoutContexts(hasTag, "Search for a given tag in Xoo files");
  83. hasTag
  84. .setDebtRemediationFunction(hasTag.debtRemediationFunctions().constantPerIssue("2min"));
  85. hasTag.createParam("tag")
  86. .setDefaultValue("xoo")
  87. .setDescription("The tag to search for");
  88. NewRule ruleWithParameters = repo.createRule("RuleWithParameters").setName("Rule with parameters");
  89. addAllDescriptionSections(ruleWithParameters,
  90. "Rule containing parameter of different types : boolean, integer, etc. For information, no issue will be linked to this rule.");
  91. ruleWithParameters.createParam("string").setType(RuleParamType.STRING);
  92. ruleWithParameters.createParam("text").setType(RuleParamType.TEXT);
  93. ruleWithParameters.createParam("boolean").setType(RuleParamType.BOOLEAN);
  94. ruleWithParameters.createParam("integer").setType(RuleParamType.INTEGER);
  95. ruleWithParameters.createParam("float").setType(RuleParamType.FLOAT);
  96. NewRule oneIssuePerLine = repo.createRule(OneIssuePerLineSensor.RULE_KEY).setName("One Issue Per Line")
  97. .setTags("line");
  98. addDescriptionSectionsWithoutContexts(oneIssuePerLine, "Generate an issue on each line of a file. It requires the metric \"lines\".");
  99. addHowToFixSectionsWithContexts(oneIssuePerLine);
  100. oneIssuePerLine
  101. .setDebtRemediationFunction(oneIssuePerLine.debtRemediationFunctions().linear("1min"))
  102. .setGapDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code")
  103. .addEducationPrincipleKeys("defense_in_depth", "never_trust_user_input");
  104. NewRule oneQuickFixPerLine = repo.createRule(OneQuickFixPerLineSensor.RULE_KEY).setName("One Quick Fix Per Line")
  105. .setTags("line");
  106. addAllDescriptionSections(oneQuickFixPerLine,
  107. "Generate an issue with quick fix available on each line of a file. It requires the metric \"lines\".");
  108. oneQuickFixPerLine
  109. .setDebtRemediationFunction(oneQuickFixPerLine.debtRemediationFunctions().linear("1min"))
  110. .setGapDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code");
  111. NewRule oneIssueOnDirPerFile = repo.createRule(OneIssueOnDirPerFileSensor.RULE_KEY).setName("One Issue On Dir Per File");
  112. addAllDescriptionSections(oneIssueOnDirPerFile,
  113. "Generate issues on directories");
  114. NewRule oneIssuePerFile = repo.createRule(OneIssuePerFileSensor.RULE_KEY).setName("One Issue Per File");
  115. oneIssuePerFile.setDebtRemediationFunction(oneIssuePerFile.debtRemediationFunctions().linear(TEN_MIN));
  116. addAllDescriptionSections(oneIssuePerFile, "Generate an issue on each file");
  117. NewRule oneIssuePerTestFile = repo.createRule(OneIssuePerTestFileSensor.RULE_KEY).setName("One Issue Per Test File")
  118. .setScope(RuleScope.TEST);
  119. oneIssuePerTestFile.setDebtRemediationFunction(oneIssuePerTestFile.debtRemediationFunctions().linear("8min"));
  120. addAllDescriptionSections(oneIssuePerTestFile, "Generate an issue on each test file");
  121. NewRule oneBugIssuePerTestLine = repo.createRule(OneBugIssuePerTestLineSensor.RULE_KEY).setName("One Bug Issue Per Test Line")
  122. .setScope(RuleScope.TEST)
  123. .setType(RuleType.BUG);
  124. addAllDescriptionSections(oneBugIssuePerTestLine, "Generate a bug issue on each line of a test file. It requires the metric \"lines\".");
  125. oneBugIssuePerTestLine
  126. .setDebtRemediationFunction(oneBugIssuePerTestLine.debtRemediationFunctions().linear("4min"));
  127. NewRule oneCodeSmellIssuePerTestLine = repo.createRule(OneCodeSmellIssuePerTestLineSensor.RULE_KEY).setName("One Code Smell Issue Per Test Line")
  128. .setScope(RuleScope.TEST)
  129. .setType(RuleType.CODE_SMELL);
  130. addAllDescriptionSections(oneCodeSmellIssuePerTestLine, "Generate a code smell issue on each line of a test file. It requires the metric \"lines\".");
  131. oneCodeSmellIssuePerTestLine
  132. .setDebtRemediationFunction(oneCodeSmellIssuePerTestLine.debtRemediationFunctions().linear("3min"));
  133. NewRule oneIssuePerDirectory = repo.createRule(OneIssuePerDirectorySensor.RULE_KEY).setName("One Issue Per Directory");
  134. oneIssuePerDirectory.setDebtRemediationFunction(oneIssuePerDirectory.debtRemediationFunctions().linear(TEN_MIN));
  135. addAllDescriptionSections(oneIssuePerDirectory, "Generate an issue on each non-empty directory");
  136. NewRule oneDayDebtPerFile = repo.createRule(OneDayDebtPerFileSensor.RULE_KEY).setName("One Day Debt Per File");
  137. oneDayDebtPerFile.setDebtRemediationFunction(oneDayDebtPerFile.debtRemediationFunctions().linear("1d"));
  138. addAllDescriptionSections(oneDayDebtPerFile, "Generate an issue on each file with a debt of one day");
  139. NewRule oneIssuePerModule = repo.createRule(OneIssuePerModuleSensor.RULE_KEY).setName("One Issue Per Module");
  140. oneIssuePerModule
  141. .setDebtRemediationFunction(oneIssuePerModule.debtRemediationFunctions().linearWithOffset("25min", "1h"))
  142. .setGapDescription("A certified architect will need roughly half an hour to start working on removal of modules, " +
  143. "then it's about one hour per module.");
  144. addAllDescriptionSections(oneIssuePerModule, "Generate an issue on each module");
  145. NewRule oneBlockerIssuePerFile = repo.createRule(OneBlockerIssuePerFileSensor.RULE_KEY).setName("One Blocker Issue Per File");
  146. addAllDescriptionSections(oneBlockerIssuePerFile, "Generate a blocker issue on each file, whatever the severity declared in the Quality profile");
  147. NewRule issueWithCustomMessage = repo.createRule(CustomMessageSensor.RULE_KEY).setName("Issue With Custom Message");
  148. addAllDescriptionSections(issueWithCustomMessage, "Generate an issue on each file with a custom message");
  149. NewRule oneIssuePerFileWithRandomAccess = repo.createRule(RandomAccessSensor.RULE_KEY).setName("One Issue Per File with Random Access");
  150. addAllDescriptionSections(oneIssuePerFileWithRandomAccess, "This issue is generated on each file");
  151. NewRule issueWithRangeAndMultipleLocations = repo.createRule(MultilineIssuesSensor.RULE_KEY).setName("Creates issues with ranges/multiple locations");
  152. addAllDescriptionSections(issueWithRangeAndMultipleLocations, "Issue with range and multiple locations");
  153. NewRule hotspotWithRangeAndMultipleLocations = repo.createRule(MultilineHotspotSensor.RULE_KEY)
  154. .setName("Creates hotspots with ranges/multiple locations")
  155. .setType(RuleType.SECURITY_HOTSPOT);
  156. addAllDescriptionSections(hotspotWithRangeAndMultipleLocations, "Hotspot with range and multiple locations");
  157. NewRule issueOnEachFileWithExtUnknown = repo.createRule(OneIssuePerUnknownFileSensor.RULE_KEY).setName("Creates issues on each file with extension 'unknown'");
  158. addAllDescriptionSections(issueOnEachFileWithExtUnknown, "This issue is generated on each file with extenstion 'unknown'");
  159. NewRule oneBugIssuePerLine = repo.createRule(OneBugIssuePerLineSensor.RULE_KEY).setName("One Bug Issue Per Line")
  160. .setType(RuleType.BUG);
  161. oneBugIssuePerLine
  162. .setDebtRemediationFunction(oneBugIssuePerLine.debtRemediationFunctions().linear("5min"));
  163. addAllDescriptionSections(oneBugIssuePerLine, "Generate a bug issue on each line of a file. It requires the metric \"lines\".");
  164. NewRule oneCodeSmellIssuePerLine = repo.createRule(OneCodeSmellIssuePerLineSensor.RULE_KEY).setName("One Code Smell Issue Per Line")
  165. .setType(RuleType.CODE_SMELL);
  166. oneCodeSmellIssuePerLine
  167. .setDebtRemediationFunction(oneCodeSmellIssuePerLine.debtRemediationFunctions().linear("9min"));
  168. addAllDescriptionSections(oneCodeSmellIssuePerLine, "Generate a code smell issue on each line of a file. It requires the metric \"lines\".");
  169. NewRule oneVulnerabilityIssuePerModule = repo.createRule(OneVulnerabilityIssuePerModuleSensor.RULE_KEY).setName("One Vulnerability Issue Per Module")
  170. .setType(RuleType.VULNERABILITY);
  171. addAllDescriptionSections(oneVulnerabilityIssuePerModule, "Generate an issue on each module");
  172. oneVulnerabilityIssuePerModule
  173. .setDebtRemediationFunction(oneVulnerabilityIssuePerModule.debtRemediationFunctions().linearWithOffset("25min", "1h"))
  174. .setGapDescription("A certified architect will need roughly half an hour to start working on removal of modules, " +
  175. "then it's about one hour per module.");
  176. NewRule templateofRule = repo
  177. .createRule("xoo-template")
  178. .setTemplate(true)
  179. .setName("Template of rule");
  180. addAllDescriptionSections(templateofRule, "Template to be overridden by custom rules");
  181. NewRule hotspot = repo.createRule(HotspotWithoutContextSensor.RULE_KEY)
  182. .setName("Find security hotspots")
  183. .setType(RuleType.SECURITY_HOTSPOT)
  184. .setActivatedByDefault(false);
  185. addAllDescriptionSections(hotspot, "Search for Security Hotspots in Xoo files");
  186. hotspot
  187. .setDebtRemediationFunction(hotspot.debtRemediationFunctions().constantPerIssue("2min"));
  188. if (version != null && version.isGreaterThanOrEqual(Version.create(9, 3))) {
  189. hotspot
  190. .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3)
  191. .addOwaspTop10(Y2021, OwaspTop10.A3, OwaspTop10.A2)
  192. .addCwe(1, 89, 123, 863);
  193. oneVulnerabilityIssuePerModule
  194. .addOwaspTop10(Y2017, OwaspTop10.A9, OwaspTop10.A10)
  195. .addOwaspTop10(Y2021, OwaspTop10.A6, OwaspTop10.A9)
  196. .addCwe(250, 564, 546, 943);
  197. }
  198. if (version != null && version.isGreaterThanOrEqual(Version.create(9, 5))) {
  199. hotspot
  200. .addPciDss(PciDssVersion.V4_0, "6.5.1", "4.1")
  201. .addPciDss(PciDssVersion.V3_2, "6.5.1", "4.2")
  202. .addPciDss(PciDssVersion.V4_0, "6.5a.1", "4.2c")
  203. .addPciDss(PciDssVersion.V3_2, "6.5a.1b", "4.2b");
  204. oneVulnerabilityIssuePerModule
  205. .addPciDss(PciDssVersion.V4_0, "10.1")
  206. .addPciDss(PciDssVersion.V3_2, "10.2")
  207. .addPciDss(PciDssVersion.V4_0, "10.1a.2b")
  208. .addPciDss(PciDssVersion.V3_2, "10.1a.2c");
  209. }
  210. if (version != null && version.isGreaterThanOrEqual(Version.create(9, 6))) {
  211. hotspot
  212. .addOwaspAsvs(OwaspAsvsVersion.V4_0, "2.8.7", "3.1.1", "4.2.2");
  213. oneVulnerabilityIssuePerModule
  214. .addOwaspAsvs(OwaspAsvsVersion.V4_0, "11.1.2", "14.5.1", "14.5.4");
  215. }
  216. NewRule hotspotWithContexts = repo.createRule(HotspotWithContextsSensor.RULE_KEY)
  217. .setName("Find security hotspots with contexts")
  218. .setType(RuleType.SECURITY_HOTSPOT)
  219. .setActivatedByDefault(false);
  220. addDescriptionSectionsWithoutContexts(hotspotWithContexts, "Search for Security Hotspots with contexts in Xoo files");
  221. addHowToFixSectionsWithContexts(hotspotWithContexts);
  222. NewRule hotspotWithSingleContext = repo.createRule(HotspotWithSingleContextSensor.RULE_KEY)
  223. .setName("Find security hotspots, how_to_fix with single context")
  224. .setType(RuleType.SECURITY_HOTSPOT)
  225. .setActivatedByDefault(false)
  226. .addDescriptionSection(howToFixSectionWithContext("single_context"));
  227. addDescriptionSectionsWithoutContexts(hotspotWithSingleContext, "Search for Security Hotspots with single context in Xoo files");
  228. repo.done();
  229. }
  230. private static void defineRulesXooExternal(Context context) {
  231. NewRepository repo = context.createExternalRepository(OneExternalIssuePerLineSensor.ENGINE_ID, Xoo.KEY).setName(OneExternalIssuePerLineSensor.ENGINE_ID);
  232. repo.createRule(OnePredefinedRuleExternalIssuePerLineSensor.RULE_ID)
  233. .setSeverity(OnePredefinedRuleExternalIssuePerLineSensor.SEVERITY)
  234. .setType(OnePredefinedRuleExternalIssuePerLineSensor.TYPE)
  235. .setScope(RuleScope.ALL)
  236. .setHtmlDescription("Generates one external issue in each line")
  237. .addDescriptionSection(descriptionSection(INTRODUCTION_SECTION_KEY, "Generates one external issue in each line"))
  238. .setName("One external issue per line")
  239. .setTags("riri", "fifi", "loulou");
  240. repo.done();
  241. }
  242. private static void addAllDescriptionSections(NewRule rule, String description) {
  243. addDescriptionSectionsWithoutContexts(rule, description);
  244. rule.addDescriptionSection(descriptionSection(HOW_TO_FIX_SECTION_KEY, "How to fix: " + description));
  245. }
  246. private static void addDescriptionSectionsWithoutContexts(NewRule rule, String description) {
  247. rule
  248. .setHtmlDescription(description)
  249. .addDescriptionSection(descriptionSection(INTRODUCTION_SECTION_KEY, "Introduction: " + description))
  250. .addDescriptionSection(descriptionSection(ROOT_CAUSE_SECTION_KEY, "Root cause: " + description))
  251. .addDescriptionSection(descriptionSection(ASSESS_THE_PROBLEM_SECTION_KEY, "Assess the problem: " + description))
  252. .addDescriptionSection(descriptionSection(RESOURCES_SECTION_KEY,
  253. "<a href=\"www.google.fr\"> Google </a><br><a href=\"https://stackoverflow.com/\"> StackOverflow</a>"))
  254. .addDescriptionSection(descriptionSection("fake_section_to_be_ignored",
  255. "fake_section_to_be_ignored"));
  256. }
  257. private static void addHowToFixSectionsWithContexts(NewRule rule) {
  258. for (String contextName : AVAILABLE_CONTEXTS) {
  259. rule.addDescriptionSection(howToFixSectionWithContext(contextName));
  260. }
  261. }
  262. private static RuleDescriptionSection descriptionSection(String sectionKey, String htmlDescription) {
  263. return RuleDescriptionSection.builder()
  264. .sectionKey(sectionKey)
  265. .htmlContent(htmlDescription)
  266. .build();
  267. }
  268. private static RuleDescriptionSection howToFixSectionWithContext(String contextName) {
  269. return RuleDescriptionSection.builder()
  270. .sectionKey(HOW_TO_FIX_SECTION_KEY)
  271. .htmlContent(String.format("This is 'How to fix?' description section for the <a href=\"https://stackoverflow.com/\"> %s</a>. " +
  272. "This text can be very long.", contextName))
  273. .context(new org.sonar.api.server.rule.Context(contextName, contextName))
  274. .build();
  275. }
  276. }