Mention explicitly that general regex aren't supported
The general regex were neither explicitly allowed nor forbidden;
add a specific note in the documentation and checks in the code
and tests for making sure that the only general regex allowed
is ^.*
Change-Id: I61d51430e5586f805a4f7691ac6c865e0afc78b8
diff --git a/README.md b/README.md
index e94a03e..a51efd3 100644
--- a/README.md
+++ b/README.md
@@ -63,3 +63,9 @@
[default]
projects = ^.*
```
+
+> **NOTE**: The `^.*` is the only regular expression supported by the virtualhost
+> module because of the potential performance implication of a generic regular expression
+> evaluation during the ACLs. Bear in mind that any possible action perform in Gerrit will
+> go through the virtualhost module filtering and therefore it is paramount to minimize the
+> potential performance impact.
diff --git a/src/main/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfig.java b/src/main/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfig.java
index d2d1cc9..3b80f7c 100644
--- a/src/main/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfig.java
+++ b/src/main/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfig.java
@@ -15,6 +15,7 @@
package com.gerritforge.gerrit.modules.virtualhost;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.project.RefPattern;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
@@ -31,6 +32,7 @@
private final Config config;
private final boolean enabled;
+ public static final String ALL_PROJECTS_REGEX = "^.*";
public final String[] defaultProjects;
@Inject
@@ -46,7 +48,7 @@
defaultProjects = new String[0];
return;
}
- defaultProjects = config.getStringList("default", null, "projects");
+ defaultProjects = validateProjects(config.getStringList("default", null, "projects"));
enabled = !config.getSubsections("server").isEmpty() || defaultProjects.length > 0;
}
@@ -55,7 +57,7 @@
return EMPTY_PROJECTS_ARRAY;
}
- String[] projects = config.getStringList("server", hostname, "projects");
+ String[] projects = validateProjects(config.getStringList("server", hostname, "projects"));
if (projects.length > 0) {
return projects;
}
@@ -63,6 +65,16 @@
return defaultProjects;
}
+ private String[] validateProjects(String[] projects) {
+ for (String project : projects) {
+ if (RefPattern.isRE(project) && !project.equals(ALL_PROJECTS_REGEX)) {
+ throw new IllegalStateException(
+ "Project regex '" + project + "' is not allowed in virtualhost.config");
+ }
+ }
+ return projects;
+ }
+
public boolean isEnabled() {
return enabled;
}
diff --git a/src/test/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfigTest.java b/src/test/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfigTest.java
new file mode 100644
index 0000000..d9ecbf2
--- /dev/null
+++ b/src/test/java/com/gerritforge/gerrit/modules/virtualhost/VirtualHostConfigTest.java
@@ -0,0 +1,80 @@
+// Copyright (C) 2024 GerritForge Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.gerritforge.gerrit.modules.virtualhost;
+
+import static com.gerritforge.gerrit.modules.virtualhost.VirtualHostConfig.ALL_PROJECTS_REGEX;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+
+import com.google.gerrit.server.config.SitePaths;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.junit.Before;
+import org.junit.Test;
+
+public class VirtualHostConfigTest {
+
+ public static final String TEST_VIRTUAL_HOST = "testhost";
+ private SitePaths testSitePaths;
+ private FileBasedConfig virtualHostFileConfig;
+
+ @Before
+ public void setup() throws IOException {
+ Path tempPath = Files.createTempDirectory("virtualhost-test-" + System.nanoTime());
+ testSitePaths = new SitePaths(tempPath);
+ virtualHostFileConfig =
+ new FileBasedConfig(
+ testSitePaths.etc_dir.resolve("virtualhost.config").toFile(), FS.DETECTED);
+ }
+
+ @Test
+ public void projectsAllowsCatchAllRegExOnDefaults() throws IOException {
+ setVirtualHostConfig("default", null, ALL_PROJECTS_REGEX);
+ assertThat(new VirtualHostConfig(testSitePaths).getProjects(TEST_VIRTUAL_HOST))
+ .isEqualTo(new String[] {ALL_PROJECTS_REGEX});
+ }
+
+ @Test
+ public void projectsAllowsCatchAllRegExOnSpecificHost() throws IOException {
+ setVirtualHostConfig("server", TEST_VIRTUAL_HOST, ALL_PROJECTS_REGEX);
+ assertThat(new VirtualHostConfig(testSitePaths).getProjects(TEST_VIRTUAL_HOST))
+ .isEqualTo(new String[] {ALL_PROJECTS_REGEX});
+ }
+
+ @Test
+ public void projectsGeneralRegExOnDefaultsShouldBeForbidden() throws IOException {
+ setVirtualHostConfig("default", null, "^ageneralregex.*$");
+ assertThrows(
+ IllegalStateException.class,
+ () -> new VirtualHostConfig(testSitePaths).getProjects(TEST_VIRTUAL_HOST));
+ }
+
+ @Test
+ public void projectsGeneralRegExOnSpecificHostShouldBeForbidden() throws IOException {
+ setVirtualHostConfig("server", TEST_VIRTUAL_HOST, "^ageneralregex.*$");
+ assertThrows(
+ IllegalStateException.class,
+ () -> new VirtualHostConfig(testSitePaths).getProjects(TEST_VIRTUAL_HOST));
+ }
+
+ private void setVirtualHostConfig(String section, String subsection, String projectsValue)
+ throws IOException {
+ virtualHostFileConfig.setString(section, subsection, "projects", projectsValue);
+ virtualHostFileConfig.save();
+ }
+}