import org.springframework.context.annotation.Bean;
public class ModuleConfigurationProvider {
+
+ private final SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter;
+
+ public ModuleConfigurationProvider(SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter) {
+ this.sonarGlobalPropertiesFilter = sonarGlobalPropertiesFilter;
+ }
+
+
@Bean("ModuleConfiguration")
public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings,
ProjectServerSettings projectServerSettings) {
settings.putAll(projectServerSettings.properties());
addScannerSideProperties(settings, module.definition());
+ settings = sonarGlobalPropertiesFilter.enforceOnlyServerSideSonarGlobalPropertiesAreUsed(settings, globalServerSettings.properties());
+
return new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
}
import org.sonar.scanner.bootstrap.GlobalServerSettings;
import org.springframework.context.annotation.Bean;
+
public class ProjectConfigurationProvider {
+
+ private final SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter;
+
+ public ProjectConfigurationProvider(SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter) {
+ this.sonarGlobalPropertiesFilter = sonarGlobalPropertiesFilter;
+ }
+
@Bean("ProjectConfiguration")
public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings,
ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) {
settings.putAll(projectServerSettings.properties());
settings.putAll(project.properties());
+ settings = sonarGlobalPropertiesFilter.enforceOnlyServerSideSonarGlobalPropertiesAreUsed(settings, globalServerSettings.properties());
+
ProjectConfiguration projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
projectSettings.complete(projectConfig);
return projectConfig;
}
+
+
}
public class ProjectServerSettingsProvider {
- private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class);
+ private static final Logger LOG = Loggers.get(ProjectServerSettingsProvider.class);
private static final String MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING = "Settings that were previously configured at " +
"sub-project level are not used anymore. Transition the settings listed in ‘General Settings -> General -> " +
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class SonarGlobalPropertiesFilter {
+
+ @VisibleForTesting
+ static final String SONAR_GLOBAL_PROPERTIES_PREFIX = "sonar.global.";
+
+ public Map<String, String> enforceOnlyServerSideSonarGlobalPropertiesAreUsed(Map<String, String> settingProperties, Map<String, String> globalServerSettingsProperties) {
+ Map<String, String> settings = getNonSonarGlobalProperties(settingProperties);
+ settings.putAll(getSonarGlobalProperties(globalServerSettingsProperties));
+ return settings;
+ }
+
+
+ private static Map<String, String> getNonSonarGlobalProperties(Map<String, String> settingProperties) {
+ return settingProperties.entrySet()
+ .stream()
+ .filter(entry -> !isSonarGlobalProperty(entry.getKey()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
+
+ private static Map<String, String> getSonarGlobalProperties(Map<String, String> properties) {
+ return properties
+ .entrySet()
+ .stream()
+ .filter(entry -> isSonarGlobalProperty(entry.getKey()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
+
+ private static boolean isSonarGlobalProperty(String propertiesCode) {
+ return propertiesCode.startsWith(SONAR_GLOBAL_PROPERTIES_PREFIX);
+ }
+
+}
module.definition(),
module,
MutableModuleSettings.class,
- new ModuleConfigurationProvider(),
+ SonarGlobalPropertiesFilter.class,
+ ModuleConfigurationProvider.class,
ModuleSensorsExecutor.class,
MutableProjectSettings.class,
ScannerProperties.class,
- new ProjectConfigurationProvider(),
+ SonarGlobalPropertiesFilter.class,
+ ProjectConfigurationProvider.class,
ProjectCoverageAndDuplicationExclusions.class,
import org.sonar.scanner.scan.ModuleConfiguration;
import org.sonar.scanner.scan.ModuleConfigurationProvider;
import org.sonar.scanner.scan.ProjectServerSettings;
+import org.sonar.scanner.scan.SonarGlobalPropertiesFilter;
import org.sonar.scanner.scm.ScmConfiguration;
import org.sonar.scanner.util.ProgressReport;
private static final Logger LOG = Loggers.get(ProjectFileIndexer.class);
private final ProjectExclusionFilters projectExclusionFilters;
+ private final SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter;
private final ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions;
private final ScmConfiguration scmConfiguration;
private final InputComponentStore componentStore;
private ProgressReport progressReport;
public ProjectFileIndexer(InputComponentStore componentStore, ProjectExclusionFilters exclusionFilters,
- InputModuleHierarchy inputModuleHierarchy, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings, ProjectServerSettings projectServerSettings,
+ SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter, InputModuleHierarchy inputModuleHierarchy, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings, ProjectServerSettings projectServerSettings,
FileIndexer fileIndexer, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, ScmConfiguration scmConfiguration) {
this.componentStore = componentStore;
+ this.sonarGlobalPropertiesFilter = sonarGlobalPropertiesFilter;
this.inputModuleHierarchy = inputModuleHierarchy;
this.globalConfig = globalConfig;
this.globalServerSettings = globalServerSettings;
private void index(DefaultInputModule module, ExclusionCounter exclusionCounter) {
// Emulate creation of module level settings
- ModuleConfiguration moduleConfig = new ModuleConfigurationProvider().provide(globalConfig, module, globalServerSettings, projectServerSettings);
+ ModuleConfiguration moduleConfig = new ModuleConfigurationProvider(sonarGlobalPropertiesFilter).provide(globalConfig, module, globalServerSettings, projectServerSettings);
ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(moduleConfig);
ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions = new ModuleCoverageAndDuplicationExclusions(moduleConfig);
if (componentStore.allModules().size() > 1) {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.bootstrap.GlobalConfiguration;
+import org.sonar.scanner.bootstrap.GlobalServerSettings;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ModuleConfigurationProviderTest {
+
+ private static final String GLOBAL_KEY_PROPERTIES_1 = "sonar.global.key1";
+ private static final String NON_GLOBAL_KEY_PROPERTIES_1 = "sonar.key1";
+ private static final String DEFAULT_KEY_PROPERTIES_1 = "default.key1";
+ private static final String GLOBAL_VALUE_PROPERTIES_1 = "Value for " + GLOBAL_KEY_PROPERTIES_1;
+ private static final String NON_GLOBAL_VALUE_PROPERTIES_1 = "Value for " + NON_GLOBAL_KEY_PROPERTIES_1;
+ private static final String DEFAULT_VALUE_1 = "Value for " + DEFAULT_KEY_PROPERTIES_1;
+
+ private static final Map<String, String> GLOBAL_SERVER_PROPERTIES = Map.of(GLOBAL_KEY_PROPERTIES_1, GLOBAL_VALUE_PROPERTIES_1);
+ private static final Map<String, String> PROJECT_SERVER_PROPERTIES = Map.of(NON_GLOBAL_KEY_PROPERTIES_1, NON_GLOBAL_VALUE_PROPERTIES_1);
+ private static final Map<String, String> DEFAULT_PROJECT_PROPERTIES = Map.of(DEFAULT_KEY_PROPERTIES_1, DEFAULT_VALUE_1);
+
+ private static final Map<String, String> ALL_PROPERTIES_MAP =
+ Stream.of(GLOBAL_SERVER_PROPERTIES, PROJECT_SERVER_PROPERTIES)
+ .flatMap(map -> map.entrySet().stream())
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+ private static final Map<String, String> PROPERTIES_AFTER_FILTERING = Map.of("aKey", "aValue");
+
+ @Mock
+ private GlobalServerSettings globalServerSettings;
+ @Mock
+ private ProjectServerSettings projectServerSettings;
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+ @Mock
+ private DefaultInputModule defaultInputProject;
+
+
+ @Mock
+ private SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter;
+
+ @InjectMocks
+ private ModuleConfigurationProvider provider;
+
+ @Before
+ public void init() {
+ when(globalConfiguration.getDefinitions()).thenReturn(new PropertyDefinitions(System2.INSTANCE));
+ }
+
+ @Test
+ public void should_concatAllPropertiesForCallFilterAndApplyFilterChanges() {
+ when(globalServerSettings.properties()).thenReturn(GLOBAL_SERVER_PROPERTIES);
+ when(projectServerSettings.properties()).thenReturn(PROJECT_SERVER_PROPERTIES);
+ when(sonarGlobalPropertiesFilter.enforceOnlyServerSideSonarGlobalPropertiesAreUsed(ALL_PROPERTIES_MAP, GLOBAL_SERVER_PROPERTIES))
+ .thenReturn(PROPERTIES_AFTER_FILTERING);
+
+ ModuleConfiguration provide = provider.provide(globalConfiguration, defaultInputProject, globalServerSettings, projectServerSettings);
+
+ verify(sonarGlobalPropertiesFilter).enforceOnlyServerSideSonarGlobalPropertiesAreUsed(ALL_PROPERTIES_MAP, GLOBAL_SERVER_PROPERTIES);
+ assertThat(provide.getOriginalProperties()).containsExactlyEntriesOf(PROPERTIES_AFTER_FILTERING);
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
+import org.sonar.scanner.bootstrap.GlobalConfiguration;
+import org.sonar.scanner.bootstrap.GlobalServerSettings;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ProjectConfigurationProviderTest {
+
+ private static final String GLOBAL_KEY_PROPERTIES_1 = "sonar.global.key1";
+ private static final String NON_GLOBAL_KEY_PROPERTIES_1 = "sonar.key1";
+ private static final String DEFAULT_KEY_PROPERTIES_1 = "default.key1";
+ private static final String GLOBAL_VALUE_PROPERTIES_1 = "Value for " + GLOBAL_KEY_PROPERTIES_1;
+ private static final String NON_GLOBAL_VALUE_PROPERTIES_1 = "Value for " + NON_GLOBAL_KEY_PROPERTIES_1;
+ private static final String DEFAULT_VALUE_1 = "Value for " + DEFAULT_KEY_PROPERTIES_1;
+
+ private static final Map<String, String> GLOBAL_SERVER_PROPERTIES = Map.of(GLOBAL_KEY_PROPERTIES_1, GLOBAL_VALUE_PROPERTIES_1);
+ private static final Map<String, String> PROJECT_SERVER_PROPERTIES = Map.of(NON_GLOBAL_KEY_PROPERTIES_1, NON_GLOBAL_VALUE_PROPERTIES_1);
+ private static final Map<String, String> DEFAULT_PROJECT_PROPERTIES = Map.of(DEFAULT_KEY_PROPERTIES_1, DEFAULT_VALUE_1);
+
+ private static final Map<String, String> ALL_PROPERTIES_MAP =
+ Stream.of(GLOBAL_SERVER_PROPERTIES, PROJECT_SERVER_PROPERTIES, DEFAULT_PROJECT_PROPERTIES)
+ .flatMap(map -> map.entrySet().stream())
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+ private static final Map<String, String> PROPERTIES_AFTER_FILTERING = Map.of("aKey", "aValue");
+
+ @Mock
+ private GlobalServerSettings globalServerSettings;
+ @Mock
+ private ProjectServerSettings projectServerSettings;
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+ @Mock
+ private MutableProjectSettings mutableProjectSettings;
+ @Mock
+ private DefaultInputProject defaultInputProject;
+ @Mock
+ private SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter;
+
+ @InjectMocks
+ private ProjectConfigurationProvider provider;
+
+
+ @Before
+ public void init() {
+ when(globalConfiguration.getDefinitions()).thenReturn(new PropertyDefinitions(System2.INSTANCE));
+ }
+
+ @Test
+ public void should_concatAllPropertiesForCallFilterAndApplyFilterChanges() {
+ when(globalServerSettings.properties()).thenReturn(GLOBAL_SERVER_PROPERTIES);
+ when(projectServerSettings.properties()).thenReturn(PROJECT_SERVER_PROPERTIES);
+ when(defaultInputProject.properties()).thenReturn(DEFAULT_PROJECT_PROPERTIES);
+ when(sonarGlobalPropertiesFilter.enforceOnlyServerSideSonarGlobalPropertiesAreUsed(ALL_PROPERTIES_MAP, GLOBAL_SERVER_PROPERTIES))
+ .thenReturn(PROPERTIES_AFTER_FILTERING);
+
+ ProjectConfiguration provide = provider.provide(defaultInputProject, globalConfiguration, globalServerSettings, projectServerSettings, mutableProjectSettings);
+
+ verify(sonarGlobalPropertiesFilter).enforceOnlyServerSideSonarGlobalPropertiesAreUsed(ALL_PROPERTIES_MAP, GLOBAL_SERVER_PROPERTIES);
+ assertThat(provide.getOriginalProperties()).containsExactlyEntriesOf(PROPERTIES_AFTER_FILTERING);
+
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import java.util.Map;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.scanner.scan.SonarGlobalPropertiesFilter.SONAR_GLOBAL_PROPERTIES_PREFIX;
+
+public class SonarGlobalPropertiesFilterTest {
+
+ private static final String SONAR_GLOBAL_KEY_1 = SONAR_GLOBAL_PROPERTIES_PREFIX + "key1";
+ private static final String SONAR_GLOBAL_VALUE_1 = "value for " + SONAR_GLOBAL_KEY_1;
+ private static final String SONAR_GLOBAL_KEY_2 = SONAR_GLOBAL_PROPERTIES_PREFIX + "key2";
+ private static final String SONAR_GLOBAL_KEY_3 = SONAR_GLOBAL_PROPERTIES_PREFIX + "key3";
+ private static final String SONAR_GLOBAL_VALUE_3 = "value for " + SONAR_GLOBAL_KEY_3;
+
+ private static final String SONAR_NON_GLOBAL_KEY_4 = "sonar.key4";
+ private static final String SONAR_NON_GLOBAL_VALUE_4 = "value for " + SONAR_NON_GLOBAL_KEY_4;
+ private static final String ANOTHER_KEY = "another key";
+ private static final String ANOTHER_VALUE = "another value";
+
+ private final SonarGlobalPropertiesFilter sonarGlobalPropertiesFilter = new SonarGlobalPropertiesFilter();
+
+ @Test
+ public void should_filterSonarGlobalProperties() {
+ Map<String, String> settingProperties = Map.of(
+ SONAR_GLOBAL_KEY_1, "shouldBeOverride",
+ SONAR_GLOBAL_KEY_2, "shouldBeRemove",
+ SONAR_NON_GLOBAL_KEY_4, SONAR_NON_GLOBAL_VALUE_4,
+ ANOTHER_KEY, ANOTHER_VALUE);
+
+ Map<String, String> globalServerSettingsProperties = Map.of(
+ SONAR_GLOBAL_KEY_1, SONAR_GLOBAL_VALUE_1,
+ SONAR_GLOBAL_KEY_3, SONAR_GLOBAL_VALUE_3,
+ SONAR_NON_GLOBAL_KEY_4, "shouldBeIgnored"
+ );
+
+ Map<String, String> properties = sonarGlobalPropertiesFilter.enforceOnlyServerSideSonarGlobalPropertiesAreUsed(settingProperties, globalServerSettingsProperties);
+
+ assertThat(properties).hasSize(4)
+ .containsEntry(SONAR_GLOBAL_KEY_1, SONAR_GLOBAL_VALUE_1)
+ .containsEntry(SONAR_GLOBAL_KEY_3, SONAR_GLOBAL_VALUE_3)
+ .containsEntry(SONAR_NON_GLOBAL_KEY_4, SONAR_NON_GLOBAL_VALUE_4)
+ .containsEntry(ANOTHER_KEY, ANOTHER_VALUE);
+
+
+ }
+}
\ No newline at end of file