*/
package org.sonar.server.telemetry;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.core.platform.EditionProvider;
+import org.sonar.core.platform.EditionProvider.Edition;
import org.sonar.server.measure.index.ProjectMeasuresStatistics;
+import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNull;
public class TelemetryData {
private final boolean inDocker;
private final Boolean hasUnanalyzedC;
private final Boolean hasUnanalyzedCpp;
+ private final List<String> customSecurityConfigs;
private TelemetryData(Builder builder) {
serverId = builder.serverId;
inDocker = builder.inDocker;
hasUnanalyzedC = builder.hasUnanalyzedC;
hasUnanalyzedCpp = builder.hasUnanalyzedCpp;
+ customSecurityConfigs = builder.customSecurityConfigs == null ? emptyList() : builder.customSecurityConfigs;
}
public String getServerId() {
return Optional.ofNullable(hasUnanalyzedCpp);
}
+ public List<String> getCustomSecurityConfigs() {
+ return customSecurityConfigs;
+ }
+
static Builder builder() {
return new Builder();
}
private Map<String, Long> almIntegrationCountByAlm;
private Long ncloc;
private Boolean usingBranches;
- private EditionProvider.Edition edition;
+ private Edition edition;
private String licenseType;
private Long installationDate;
private String installationVersion;
private boolean inDocker = false;
private Boolean hasUnanalyzedC;
private Boolean hasUnanalyzedCpp;
+ private List<String> customSecurityConfigs;
private Builder() {
// enforce static factory method
return this;
}
- Builder setEdition(@Nullable EditionProvider.Edition edition) {
+ Builder setEdition(@Nullable Edition edition) {
this.edition = edition;
return this;
}
return this;
}
+ Builder setCustomSecurityConfigs(List<String> customSecurityConfigs) {
+ this.customSecurityConfigs = customSecurityConfigs;
+ return this;
+ }
+
TelemetryData build() {
requireNonNull(serverId);
requireNonNull(version);
});
json.endArray();
+ if (!statistics.getCustomSecurityConfigs().isEmpty()) {
+ json.name("customSecurityConfig");
+ json.beginArray();
+ json.values(statistics.getCustomSecurityConfigs());
+ json.endArray();
+ }
+
statistics.hasUnanalyzedC().ifPresent(hasUnanalyzedC -> json.prop("hasUnanalyzedC", hasUnanalyzedC));
statistics.hasUnanalyzedCpp().ifPresent(hasUnanalyzedCpp -> json.prop("hasUnanalyzedCpp", hasUnanalyzedCpp));
if (statistics.getInstallationDate() != null) {
"}");
}
+ @Test
+ public void writes_security_custom_config() {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setCustomSecurityConfigs(Arrays.asList("php", "java"))
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"customSecurityConfig\": [\"php\", \"java\"]" +
+ "}");
+ }
+
@DataProvider
public static Object[][] allEditions() {
return Arrays.stream(EditionProvider.Edition.values())
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.server.ServerSide;
import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.server.user.index.UserIndex;
import org.sonar.server.user.index.UserQuery;
+import static java.util.Arrays.asList;
import static java.util.Optional.ofNullable;
import static org.apache.commons.lang.StringUtils.startsWith;
import static org.sonar.core.platform.EditionProvider.Edition.COMMUNITY;
+import static org.sonar.core.platform.EditionProvider.Edition.DATACENTER;
+import static org.sonar.core.platform.EditionProvider.Edition.ENTERPRISE;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_CPP_KEY;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_C_KEY;
private final UserIndex userIndex;
private final ProjectMeasuresIndex projectMeasuresIndex;
private final PlatformEditionProvider editionProvider;
+ private final Configuration configuration;
private final InternalProperties internalProperties;
private final DockerSupport dockerSupport;
@CheckForNull
private final LicenseReader licenseReader;
public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
- PlatformEditionProvider editionProvider, InternalProperties internalProperties, DockerSupport dockerSupport) {
- this(server, dbClient, pluginRepository, userIndex, projectMeasuresIndex, editionProvider, internalProperties, dockerSupport, null);
+ PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration, DockerSupport dockerSupport) {
+ this(server, dbClient, pluginRepository, userIndex, projectMeasuresIndex, editionProvider, internalProperties, configuration, dockerSupport, null);
}
public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
- PlatformEditionProvider editionProvider, InternalProperties internalProperties,
+ PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration,
DockerSupport dockerSupport, @Nullable LicenseReader licenseReader) {
this.server = server;
this.dbClient = dbClient;
this.projectMeasuresIndex = projectMeasuresIndex;
this.editionProvider = editionProvider;
this.internalProperties = internalProperties;
+ this.configuration = configuration;
this.dockerSupport = dockerSupport;
this.licenseReader = licenseReader;
}
data.setAlmIntegrationCountByAlm(countAlmUsage(dbSession));
}
+
+ setSecurityCustomConfigIfPresent(data);
+
Optional<String> installationDateProperty = internalProperties.read(InternalProperties.INSTALLATION_DATE);
installationDateProperty.ifPresent(s -> data.setInstallationDate(Long.valueOf(s)));
Optional<String> installationVersionProperty = internalProperties.read(InternalProperties.INSTALLATION_VERSION);
return data.build();
}
+ private void setSecurityCustomConfigIfPresent(TelemetryData.Builder data) {
+ editionProvider.get()
+ .filter(edition -> asList(ENTERPRISE, DATACENTER).contains(edition))
+ .ifPresent(edition -> {
+ List<String> customSecurityConfigs = new LinkedList<>();
+ configuration.get("sonar.security.config.javasecurity")
+ .ifPresent(s -> customSecurityConfigs.add("java"));
+ configuration.get("sonar.security.config.phpsecurity")
+ .ifPresent(s -> customSecurityConfigs.add("php"));
+ configuration.get("sonar.security.config.pythonsecurity")
+ .ifPresent(s -> customSecurityConfigs.add("python"));
+ configuration.get("sonar.security.config.roslyn.sonaranalyzer.security.cs")
+ .ifPresent(s -> customSecurityConfigs.add("csharp"));
+ data.setCustomSecurityConfigs(customSecurityConfigs);
+ });
+ }
+
private Map<String, Long> countAlmUsage(DbSession dbSession) {
return dbClient.almSettingDao().selectAll(dbSession).stream()
.collect(Collectors.groupingBy(almSettingDto -> {
import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.config.Configuration;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.platform.PluginInfo;
import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
import static org.sonar.core.platform.EditionProvider.Edition.COMMUNITY;
import static org.sonar.core.platform.EditionProvider.Edition.DEVELOPER;
+import static org.sonar.core.platform.EditionProvider.Edition.ENTERPRISE;
import static org.sonar.db.component.BranchType.BRANCH;
import static org.sonar.db.component.BranchType.PULL_REQUEST;
import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_CPP_KEY;
private final FakeServer server = new FakeServer();
private final PluginRepository pluginRepository = mock(PluginRepository.class);
+ private final Configuration configuration = mock(Configuration.class);
private final TestSystem2 system2 = new TestSystem2().setNow(System.currentTimeMillis());
private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
private final DockerSupport dockerSupport = mock(DockerSupport.class);
private final LicenseReader licenseReader = mock(LicenseReader.class);
private final TelemetryDataLoader communityUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
- new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, dockerSupport, null);
+ new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, configuration, dockerSupport, null);
private final TelemetryDataLoader commercialUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
- new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, dockerSupport, licenseReader);
+ new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, configuration, dockerSupport, licenseReader);
@Test
public void send_telemetry_data() {
entry("java", 500L), entry("kotlin", 2500L), entry("js", 50L));
assertThat(data.isInDocker()).isFalse();
assertThat(data.getAlmIntegrationCountByAlm())
- .containsEntry("azure_devops_server", 1L)
- .containsEntry("azure_devops_cloud", 1L)
- .containsEntry("bitbucket_server", 1L)
- .containsEntry("bitbucket_cloud", 1L)
- .containsEntry("gitlab_server", 1L)
- .containsEntry("gitlab_cloud", 1L)
- .containsEntry("github_cloud", 1L)
- .containsEntry("github_server", 1L);
+ .containsEntry("azure_devops_server", 1L)
+ .containsEntry("azure_devops_cloud", 1L)
+ .containsEntry("bitbucket_server", 1L)
+ .containsEntry("bitbucket_cloud", 1L)
+ .containsEntry("gitlab_server", 1L)
+ .containsEntry("gitlab_cloud", 1L)
+ .containsEntry("github_cloud", 1L)
+ .containsEntry("github_server", 1L);
}
private void assertDatabaseMetadata(TelemetryData.Database database) {
assertThat(data.hasUnanalyzedCpp().get()).isFalse();
}
+ @Test
+ public void populate_security_custom_config_for_languages_on_enterprise() {
+ when(editionProvider.get()).thenReturn(Optional.of(ENTERPRISE));
+
+ when(configuration.get("sonar.security.config.javasecurity")).thenReturn(Optional.of("{}"));
+ when(configuration.get("sonar.security.config.phpsecurity")).thenReturn(Optional.of("{}"));
+ when(configuration.get("sonar.security.config.pythonsecurity")).thenReturn(Optional.of("{}"));
+ when(configuration.get("sonar.security.config.roslyn.sonaranalyzer.security.cs")).thenReturn(Optional.of("{}"));
+
+ TelemetryData data = commercialUnderTest.load();
+
+ assertThat(data.getCustomSecurityConfigs())
+ .containsExactlyInAnyOrder("java", "php", "python", "csharp");
+ }
+
+ @Test
+ public void skip_security_custom_config_on_community() {
+ when(editionProvider.get()).thenReturn(Optional.of(COMMUNITY));
+
+ TelemetryData data = communityUnderTest.load();
+
+ assertThat(data.getCustomSecurityConfigs()).isEmpty();
+ }
+
private PluginInfo newPlugin(String key, String version) {
return new PluginInfo(key)
.setVersion(Version.create(version));