"DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
"GAP_DESCRIPTION" VARCHAR(4000),
"SYSTEM_TAGS" VARCHAR(4000),
+ "SECURITY_STANDARDS" VARCHAR(4000),
"RULE_TYPE" TINYINT,
"CREATED_AT" BIGINT,
"UPDATED_AT" BIGINT
private String defRemediationBaseEffort;
private String gapDescription;
private String systemTags;
+ private String securityStandards;
private int type;
private Scope scope;
return this;
}
+ public Set<String> getSecurityStandards() {
+ return securityStandards == null ? new HashSet<>() : new TreeSet<>(Arrays.asList(StringUtils.split(securityStandards, ',')));
+ }
+
+ private String getSecurityStandardsField() {
+ return securityStandards;
+ }
+
+ void setSecurityStandardsField(String s) {
+ securityStandards = s;
+ }
+
+ public RuleDefinitionDto setSecurityStandards(Set<String> standards) {
+ this.securityStandards = standards.isEmpty() ? null : StringUtils.join(standards, ',');
+ return this;
+ }
+
public int getType() {
return type;
}
return this;
}
+ public RuleDto setSecurityStandards(Set<String> standards) {
+ this.definition.setSecurityStandards(standards);
+ return this;
+ }
+
public int getType() {
return definition.getType();
}
definition.setSystemTagsField(s);
}
+ public Set<String> getSecurityStandards() {
+ return definition.getSecurityStandards();
+ }
+
+ /**
+ * Used in MyBatis mapping.
+ */
+ private void setSecurityStandardsField(String s) {
+ definition.setSecurityStandardsField(s);
+ }
+
public long getCreatedAt() {
return definition.getCreatedAt();
}
private RuleStatus status;
private boolean isTemplate;
private String systemTags;
+ private String securityStandards;
private String templateRuleKey;
private String templateRepository;
private String internalKey;
private long updatedAt;
private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();
+ private static final Splitter SECURITY_STANDARDS_SPLITTER = TAGS_SPLITTER;
public Integer getId() {
return id;
return systemTags;
}
+ public String getSecurityStandards() {
+ return securityStandards;
+ }
+
public String getTemplateRuleKey() {
return templateRuleKey;
}
public Set<String> getSystemTagsAsSet() {
return ImmutableSet.copyOf(TAGS_SPLITTER.split(systemTags == null ? "" : systemTags));
}
+
+ public Set<String> getSecurityStandardsAsSet() {
+ return ImmutableSet.copyOf(SECURITY_STANDARDS_SPLITTER.split(securityStandards == null ? "" : securityStandards));
+ }
}
r.def_remediation_base_effort as "defRemediationBaseEffort",
r.gap_description as "gapDescription",
r.system_tags as "systemTagsField",
+ r.security_standards as "securityStandardsField",
r.rule_type as "type",
r.plugin_key as "pluginKey",
r.scope,
r.is_template as "isTemplate",
r.is_external as "isExternal",
r.system_tags as "systemTags",
+ r.security_standards as "securityStandards",
t.plugin_rule_key as "templateRuleKey",
t.plugin_name as "templateRepository",
r.plugin_config_key as "internalKey",
def_remediation_base_effort,
gap_description,
system_tags,
+ security_standards,
rule_type,
scope,
created_at,
#{defRemediationBaseEffort,jdbcType=VARCHAR},
#{gapDescription,jdbcType=VARCHAR},
#{systemTagsField,jdbcType=VARCHAR},
+ #{securityStandardsField,jdbcType=VARCHAR},
#{type,jdbcType=TINYINT},
#{scope,jdbcType=VARCHAR},
#{createdAt,jdbcType=BIGINT},
def_remediation_base_effort=#{defRemediationBaseEffort,jdbcType=VARCHAR},
gap_description=#{gapDescription,jdbcType=VARCHAR},
system_tags=#{systemTagsField,jdbcType=VARCHAR},
+ security_standards=#{securityStandardsField,jdbcType=VARCHAR},
scope=#{scope,jdbcType=VARCHAR},
rule_type=#{type,jdbcType=TINYINT},
updated_at=#{updatedAt,jdbcType=BIGINT}
assertThat(actual.getDefRemediationBaseEffort()).isEqualTo(expected.getDefRemediationBaseEffort());
assertThat(actual.getGapDescription()).isEqualTo(expected.getGapDescription());
assertThat(actual.getSystemTags()).isEqualTo(expected.getSystemTags());
+ assertThat(actual.getSecurityStandards()).isEqualTo(expected.getSecurityStandards());
assertThat(actual.getType()).isEqualTo(expected.getType());
assertThat(actual.getCreatedAt()).isEqualTo(expected.getCreatedAt());
assertThat(actual.getUpdatedAt()).isEqualTo(expected.getUpdatedAt());
.setDefRemediationBaseEffort("10h")
.setGapDescription("squid.S115.effortToFix")
.setSystemTags(newHashSet("systag1", "systag2"))
+ .setSecurityStandards(newHashSet("owaspTop10:a1", "cwe:123"))
.setType(RuleType.BUG)
.setScope(Scope.ALL)
.setCreatedAt(1_500_000_000_000L)
assertThat(ruleDto.getDefRemediationBaseEffort()).isEqualTo("10h");
assertThat(ruleDto.getGapDescription()).isEqualTo("squid.S115.effortToFix");
assertThat(ruleDto.getSystemTags()).containsOnly("systag1", "systag2");
+ assertThat(ruleDto.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123");
assertThat(ruleDto.getScope()).isEqualTo(Scope.ALL);
assertThat(ruleDto.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(ruleDto.getCreatedAt()).isEqualTo(1_500_000_000_000L);
.setDefRemediationBaseEffort("10h")
.setGapDescription("squid.S115.effortToFix")
.setSystemTags(newHashSet("systag1", "systag2"))
+ .setSecurityStandards(newHashSet("owaspTop10:a1", "cwe:123"))
.setScope(Scope.ALL)
.setType(RuleType.BUG)
.setUpdatedAt(2_000_000_000_000L);
assertThat(ruleDto.getDefRemediationBaseEffort()).isEqualTo("10h");
assertThat(ruleDto.getGapDescription()).isEqualTo("squid.S115.effortToFix");
assertThat(ruleDto.getSystemTags()).containsOnly("systag1", "systag2");
+ assertThat(ruleDto.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123");
assertThat(ruleDto.getScope()).isEqualTo(Scope.ALL);
assertThat(ruleDto.getType()).isEqualTo(RuleType.BUG.getDbConstant());
assertThat(ruleDto.getCreatedAt()).isEqualTo(1_500_000_000_000L);
assertThat(ruleDto.getGapDescription()).isNull();
assertThat(ruleDto.getTags()).containsOnly("tag1", "tag2");
assertThat(ruleDto.getSystemTags()).isEmpty();
+ assertThat(ruleDto.getSecurityStandards()).isEmpty();
assertThat(ruleDto.getType()).isEqualTo(0);
assertThat(ruleDto.getCreatedAt()).isEqualTo(3_500_000_000_000L);
assertThat(ruleDto.getUpdatedAt()).isEqualTo(4_000_000_000_000L);
assertThat(ruleDto.getGapDescription()).isNull();
assertThat(ruleDto.getTags()).isEmpty();
assertThat(ruleDto.getSystemTags()).isEmpty();
+ assertThat(ruleDto.getSecurityStandards()).isEmpty();
assertThat(ruleDto.getType()).isEqualTo(0);
assertThat(ruleDto.getCreatedAt()).isEqualTo(3_500_000_000_000L);
assertThat(ruleDto.getUpdatedAt()).isEqualTo(4_000_000_000_000L);
assertThat(ruleDto.getGapDescription()).isNull();
assertThat(ruleDto.getTags()).containsOnly("tag1", "tag2");
assertThat(ruleDto.getSystemTags()).isEmpty();
+ assertThat(ruleDto.getSecurityStandards()).isEmpty();
assertThat(ruleDto.getType()).isEqualTo(0);
assertThat(ruleDto.getCreatedAt()).isEqualTo(3_500_000_000_000L);
assertThat(ruleDto.getUpdatedAt()).isEqualTo(7_000_000_000_000L);
assertThat(firstRule.isExternal()).isFalse();
assertThat(firstRule.isTemplate()).isEqualTo(r1.isTemplate());
assertThat(firstRule.getSystemTagsAsSet()).isEqualTo(r1.getSystemTags());
+ assertThat(firstRule.getSecurityStandardsAsSet()).isEqualTo(r1.getSecurityStandards());
assertThat(firstRule.getTemplateRuleKey()).isNull();
assertThat(firstRule.getTemplateRepository()).isNull();
assertThat(firstRule.getInternalKey()).isEqualTo(r1.getConfigKey());
assertThat(firstRule.getStatus()).isEqualTo(r1.getStatus());
assertThat(firstRule.isTemplate()).isEqualTo(r1.isTemplate());
assertThat(firstRule.getSystemTagsAsSet()).isEqualTo(r1.getSystemTags());
+ assertThat(firstRule.getSecurityStandardsAsSet()).isEqualTo(r1.getSecurityStandards());
assertThat(firstRule.getInternalKey()).isEqualTo(r1.getConfigKey());
assertThat(firstRule.getLanguage()).isEqualTo(r1.getLanguage());
assertThat(firstRule.getType()).isEqualTo(r1.getType());
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v73;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+@SupportsBlueGreen
+public class AddSecurityStandardsToRules extends DdlChange {
+
+ private static final String TABLE_NAME = "rules";
+ private static final String COLUMN_NAME = "security_standards";
+ private static final int COLUMN_LENGTH = 4000;
+
+ public AddSecurityStandardsToRules(Database db) {
+ super(db);
+ }
+
+ @Override public void execute(Context context) throws SQLException {
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName(COLUMN_NAME)
+ .setIsNullable(true)
+ .setLimit(COLUMN_LENGTH)
+ .build())
+ .build());
+ }
+}
.add(2205, "Add 'from hotspot' flag to issues", AddFromHotspotFlagToIssues.class)
.add(2206, "Add SUBSCRIPTION column to ORGANIZATIONS table", AddSubscriptionToOrganizations.class)
.add(2207, "Populate SUBSCRIPTION in ORGANIZATIONS", PopulateSubscriptionOnOrganizations.class)
+ .add(2208, "Add rules.security_standards", AddSecurityStandardsToRules.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v73;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.version.v72.AddOrganizationUuidToUsers;
+
+import static java.sql.Types.VARCHAR;
+
+public class AddSecurityStandardsToRulesTest {
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AddSecurityStandardsToRulesTest.class, "rules.sql");
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AddSecurityStandardsToRules underTest = new AddSecurityStandardsToRules(db.database());
+
+ @Test
+ public void column_is_added_to_table() throws SQLException {
+ underTest.execute();
+
+ db.assertColumnDefinition("rules", "security_standards", VARCHAR, 4000, true);
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+}
--- /dev/null
+CREATE TABLE "RULES" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "PLUGIN_KEY" VARCHAR(200),
+ "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+ "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+ "DESCRIPTION" VARCHAR(16777215),
+ "DESCRIPTION_FORMAT" VARCHAR(20),
+ "PRIORITY" INTEGER,
+ "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+ "IS_EXTERNAL" BOOLEAN,
+ "TEMPLATE_ID" INTEGER,
+ "PLUGIN_CONFIG_KEY" VARCHAR(200),
+ "NAME" VARCHAR(200),
+ "STATUS" VARCHAR(40),
+ "LANGUAGE" VARCHAR(20),
+ "SCOPE" VARCHAR(20) NOT NULL,
+ "DEF_REMEDIATION_FUNCTION" VARCHAR(20),
+ "DEF_REMEDIATION_GAP_MULT" VARCHAR(20),
+ "DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
+ "GAP_DESCRIPTION" VARCHAR(4000),
+ "SYSTEM_TAGS" VARCHAR(4000),
+ "RULE_TYPE" TINYINT,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY");
.setGapDescription(templateRuleDto.getGapDescription())
.setScope(templateRuleDto.getScope())
.setSystemTags(templateRuleDto.getSystemTags())
+ .setSecurityStandards(templateRuleDto.getSecurityStandards())
.setCreatedAt(system2.now())
.setUpdatedAt(system2.now());
dbClient.ruleDao().insert(dbSession, ruleDefinition);
assertThat(rule.getGapDescription()).isEqualTo("desc");
assertThat(rule.getTags()).containsOnly("usertag1", "usertag2");
assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4");
+ assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123");
List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey);
assertThat(params).hasSize(1);
.setGapDescription("desc")
.setTags(Sets.newHashSet("usertag1", "usertag2"))
.setSystemTags(Sets.newHashSet("tag1", "tag4"))
+ .setSecurityStandards(Sets.newHashSet("owaspTop10:a1", "cwe:123"))
.setCreatedAt(new Date().getTime())
.setUpdatedAt(new Date().getTime());
dbTester.rules().insert(templateRule.getDefinition());