From 70aa2df792098e1599cb2ca457b6d829739b3c3f Mon Sep 17 00:00:00 2001 From: Eric Giffon Date: Wed, 2 Aug 2023 17:18:30 +0200 Subject: [PATCH] SONAR-20075 Remove null chars from provider command output --- .../telemetry/CloudUsageDataProvider.java | 20 ++++++++++------ .../telemetry/CloudUsageDataProviderTest.java | 24 ++++++++++++++++--- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java index dd10f981ab5..49b390ba4e5 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java @@ -32,7 +32,9 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.util.Collection; import java.util.Scanner; +import java.util.function.Supplier; import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; @@ -65,27 +67,29 @@ public class CloudUsageDataProvider { static final String SONAR_HELM_CHART_VERSION = "SONAR_HELM_CHART_VERSION"; static final String DOCKER_RUNNING = "DOCKER_RUNNING"; private static final String[] KUBERNETES_PROVIDER_COMMAND = {"bash", "-c", "uname -r"}; + private static final int KUBERNETES_PROVIDER_MAX_SIZE = 100; private final ContainerSupport containerSupport; private final System2 system2; private final Paths2 paths2; + private final Supplier processBuilderSupplier; private OkHttpClient httpClient; private TelemetryData.CloudUsage cloudUsageData; @Inject public CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2) { - this.containerSupport = containerSupport; - this.system2 = system2; - this.paths2 = paths2; + this(containerSupport, system2, paths2, ProcessBuilder::new, null); if (isOnKubernetes()) { initHttpClient(); } } @VisibleForTesting - CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2, OkHttpClient httpClient) { + CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2, Supplier processBuilderSupplier, + @Nullable OkHttpClient httpClient) { this.containerSupport = containerSupport; this.system2 = system2; this.paths2 = paths2; + this.processBuilderSupplier = processBuilderSupplier; this.httpClient = httpClient; } @@ -208,12 +212,14 @@ public class CloudUsageDataProvider { } @CheckForNull - private static String getKubernetesProvider() { + private String getKubernetesProvider() { try { - Process process = new ProcessBuilder().command(KUBERNETES_PROVIDER_COMMAND).start(); + Process process = processBuilderSupplier.get().command(KUBERNETES_PROVIDER_COMMAND).start(); try (Scanner scanner = new Scanner(process.getInputStream(), UTF_8)) { scanner.useDelimiter("\n"); - return scanner.next(); + // Null characters can be present in the output on Windows + String output = scanner.next().replace("\u0000", ""); + return StringUtils.abbreviate(output, KUBERNETES_PROVIDER_MAX_SIZE); } finally { process.destroy(); } diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java index 823848ed9e7..f7a22cdab58 100644 --- a/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java +++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/CloudUsageDataProviderTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.telemetry; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Paths; @@ -55,7 +56,9 @@ public class CloudUsageDataProviderTest { private final Paths2 paths2 = Mockito.mock(Paths2.class); private final OkHttpClient httpClient = Mockito.mock(OkHttpClient.class); private final ContainerSupport containerSupport = mock(ContainerSupport.class); - private final CloudUsageDataProvider underTest = new CloudUsageDataProvider(containerSupport, system2, paths2, httpClient); + private final ProcessBuilder processBuilder = mock(ProcessBuilder.class); + private final CloudUsageDataProvider underTest = new CloudUsageDataProvider(containerSupport, system2, paths2, () -> processBuilder, + httpClient); @Before public void setUp() throws Exception { @@ -147,8 +150,23 @@ public class CloudUsageDataProviderTest { } @Test - public void kubernetesProvider_shouldReturnValue() { - assertThat(underTest.getCloudUsage().kubernetesProvider()).isNotBlank(); + public void kubernetesProvider_shouldReturnValue() throws IOException { + Process processMock = mock(Process.class); + when(processMock.getInputStream()).thenReturn(new ByteArrayInputStream("some-provider".getBytes())); + when(processBuilder.command(any(String[].class))).thenReturn(processBuilder); + when(processBuilder.start()).thenReturn(processMock); + + assertThat(underTest.getCloudUsage().kubernetesProvider()).isEqualTo("some-provider"); + } + + @Test + public void kubernetesProvider_whenValueContainsNullChars_shouldReturnValueWithoutNullChars() throws IOException { + Process processMock = mock(Process.class); + when(processMock.getInputStream()).thenReturn(new ByteArrayInputStream("so\u0000me-prov\u0000ider".getBytes())); + when(processBuilder.command(any(String[].class))).thenReturn(processBuilder); + when(processBuilder.start()).thenReturn(processMock); + + assertThat(underTest.getCloudUsage().kubernetesProvider()).isEqualTo("some-provider"); } @Test -- 2.39.5