Browse Source

SONAR-10986 Extend RulesDefinitions API to support security standards (#466)

tags/7.5
Janos Gyerik 6 years ago
parent
commit
2a185ff22d

+ 1
- 0
server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl View File

@@ -212,6 +212,7 @@ CREATE TABLE "RULES" (
"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

+ 18
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java View File

@@ -55,6 +55,7 @@ public class RuleDefinitionDto {
private String defRemediationBaseEffort;
private String gapDescription;
private String systemTags;
private String securityStandards;
private int type;
private Scope scope;

@@ -277,6 +278,23 @@ public class RuleDefinitionDto {
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;
}

+ 16
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java View File

@@ -260,6 +260,11 @@ public class RuleDto {
return this;
}

public RuleDto setSecurityStandards(Set<String> standards) {
this.definition.setSecurityStandards(standards);
return this;
}

public int getType() {
return definition.getType();
}
@@ -285,6 +290,17 @@ public class RuleDto {
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();
}

+ 10
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleForIndexingDto.java View File

@@ -39,6 +39,7 @@ public class RuleForIndexingDto {
private RuleStatus status;
private boolean isTemplate;
private String systemTags;
private String securityStandards;
private String templateRuleKey;
private String templateRepository;
private String internalKey;
@@ -49,6 +50,7 @@ public class RuleForIndexingDto {
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;
@@ -90,6 +92,10 @@ public class RuleForIndexingDto {
return systemTags;
}

public String getSecurityStandards() {
return securityStandards;
}

public String getTemplateRuleKey() {
return templateRuleKey;
}
@@ -138,4 +144,8 @@ public class RuleForIndexingDto {
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));
}
}

+ 5
- 0
server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml View File

@@ -22,6 +22,7 @@
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,
@@ -253,6 +254,7 @@
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",
@@ -305,6 +307,7 @@
def_remediation_base_effort,
gap_description,
system_tags,
security_standards,
rule_type,
scope,
created_at,
@@ -329,6 +332,7 @@
#{defRemediationBaseEffort,jdbcType=VARCHAR},
#{gapDescription,jdbcType=VARCHAR},
#{systemTagsField,jdbcType=VARCHAR},
#{securityStandardsField,jdbcType=VARCHAR},
#{type,jdbcType=TINYINT},
#{scope,jdbcType=VARCHAR},
#{createdAt,jdbcType=BIGINT},
@@ -356,6 +360,7 @@
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}

+ 10
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java View File

@@ -370,6 +370,7 @@ public class RuleDaoTest {
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());
@@ -490,6 +491,7 @@ public class RuleDaoTest {
.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)
@@ -516,6 +518,7 @@ public class RuleDaoTest {
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);
@@ -544,6 +547,7 @@ public class RuleDaoTest {
.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);
@@ -569,6 +573,7 @@ public class RuleDaoTest {
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);
@@ -623,6 +628,7 @@ public class RuleDaoTest {
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);
@@ -681,6 +687,7 @@ public class RuleDaoTest {
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);
@@ -713,6 +720,7 @@ public class RuleDaoTest {
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);
@@ -848,6 +856,7 @@ public class RuleDaoTest {
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());
@@ -927,6 +936,7 @@ public class RuleDaoTest {
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());

+ 49
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v73/AddSecurityStandardsToRules.java View File

@@ -0,0 +1,49 @@
/*
* 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());
}
}

+ 1
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v73/DbVersion73.java View File

@@ -35,6 +35,7 @@ public class DbVersion73 implements DbVersion {
.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)
;
}
}

+ 56
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v73/AddSecurityStandardsToRulesTest.java View File

@@ -0,0 +1,56 @@
/*
* 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();
}

}

+ 26
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v73/AddSecurityStandardsToRulesTest/rules.sql View File

@@ -0,0 +1,26 @@
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");

+ 1
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java View File

@@ -170,6 +170,7 @@ public class RuleCreator {
.setGapDescription(templateRuleDto.getGapDescription())
.setScope(templateRuleDto.getScope())
.setSystemTags(templateRuleDto.getSystemTags())
.setSecurityStandards(templateRuleDto.getSecurityStandards())
.setCreatedAt(system2.now())
.setUpdatedAt(system2.now());
dbClient.ruleDao().insert(dbSession, ruleDefinition);

+ 2
- 0
server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorTest.java View File

@@ -103,6 +103,7 @@ public class RuleCreatorTest {
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);
@@ -468,6 +469,7 @@ public class RuleCreatorTest {
.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());

Loading…
Cancel
Save