changeset 980:1168c4c64d49

Merge branch Indore-2017.2.x
author Dmitry Neverov <dmitry.neverov@gmail.com>
date Wed, 24 Jan 2018 17:38:56 +0100
parents 7bf4d943d5bb (current diff) 2b1bd4bca6ad (diff)
children ec20a7691c8b
files mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersion.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java mercurial-dsl/HgVcsRoot.xml mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialUrlSupport.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialPatchTestCase.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepoTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java
diffstat 9 files changed, 108 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/README.txt	Mon Jan 22 11:39:20 2018 +0100
+++ b/README.txt	Wed Jan 24 17:38:56 2018 +0100
@@ -5,5 +5,4 @@
 
 TeamCity 4.x and later
 
-Download mercurial-server.zip and put it into the .BuildServer/plugins folder. Restart server.
-
+Download mercurial-server.zip and put it into the .BuildServer/plugins folder. Restart server.
\ No newline at end of file
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Wed Jan 24 17:38:56 2018 +0100
@@ -43,6 +43,7 @@
 
   String SHOW_CUSTOM_CLONE_PATH = "teamcity.hg.showCustomClonePath";
   String CUSTOM_CLONE_PATH_ENABLED = "teamcity.hg.customClonePathEnabled";
+  String CUSTOM_CLONE_PATH_WHITELIST = "teamcity.hg.customClonePathWhitelist";
   String CUSTOM_CACHES_DIR = "teamcity.hg.customCachesDir";
   String CUSTOM_HG_PATH_ENABLED = "teamcity.hg.customHgPathEnabled";
   String CUSTOM_HG_CONFIG_ENABLED = "teamcity.hg.customConfigEnabled";
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java	Wed Jan 24 17:38:56 2018 +0100
@@ -25,6 +25,7 @@
 
 import java.io.File;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -214,8 +215,11 @@
   }
 
   private String readCustomClonePath() {
-    if (TeamCityProperties.getBooleanOrTrue(Constants.CUSTOM_CLONE_PATH_ENABLED))
-      return getProperty(Constants.SERVER_CLONE_PATH_PROP);
+    String clonePath = getProperty(Constants.SERVER_CLONE_PATH_PROP);
+    if (TeamCityProperties.getBoolean(Constants.CUSTOM_CLONE_PATH_ENABLED))
+      return clonePath;
+    if (isAllowedCustomClonePath(clonePath))
+      return clonePath;
     return null;
   }
 
@@ -256,4 +260,26 @@
     PURGE_UNKNOWN,
     PURGE_ALL
   }
+
+
+  public static boolean hasCustomClonePathWhitelist() {
+    return StringUtil.isNotEmpty(TeamCityProperties.getProperty(Constants.CUSTOM_CLONE_PATH_WHITELIST));
+  }
+
+  public static boolean isAllowedCustomClonePath(@Nullable String path) {
+    if (StringUtil.isEmptyOrSpaces(path))
+      return false;
+    String whitelist = TeamCityProperties.getProperty(Constants.CUSTOM_CLONE_PATH_WHITELIST);
+    if (StringUtil.isEmpty(whitelist))
+      return false;
+    List<String> paths = StringUtil.split(whitelist, ";");
+    for (String p : paths) {
+      if (p.endsWith("/*")) {
+        return new File(path).getParentFile().equals(new File(p.substring(0, p.length() - 2)));
+      } else if (p.equals(path)) {
+        return true;
+      }
+    }
+    return false;
+  }
 }
--- a/mercurial-server/resources/buildServerResources/mercurialSettings.jsp	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-server/resources/buildServerResources/mercurialSettings.jsp	Wed Jan 24 17:38:56 2018 +0100
@@ -1,6 +1,8 @@
 <%@ page import="jetbrains.buildServer.serverSide.TeamCityProperties" %>
 <%@ page import="jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants" %>
 <%@ page import="jetbrains.buildServer.util.StringUtil" %>
+<%@ page import="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerPluginConfigImpl" %>
+<%@ page import="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot" %>
 <%@include file="/include.jsp"%>
 <%@ taglib prefix="props" tagdir="/WEB-INF/tags/props" %>
 <%--
@@ -28,9 +30,10 @@
 }
 </script>
 <c:set var="subreposGloballyDisabled" value="<%= !TeamCityProperties.getBooleanOrTrue(Constants.GLOBAL_DETECT_SUBREPO_CHANGES) %>"/>
-<c:set var="showCustomClonePath" value="<%= TeamCityProperties.getBooleanOrTrue(Constants.CUSTOM_CLONE_PATH_ENABLED) &&
-                                            (TeamCityProperties.getBoolean(Constants.SHOW_CUSTOM_CLONE_PATH)
-                                            || !StringUtil.isEmpty(propertiesBean.getProperties().get(Constants.SERVER_CLONE_PATH_PROP))) %>"/>
+<c:set var="showCustomClonePath" value="<%=
+  TeamCityProperties.getBoolean(Constants.CUSTOM_CLONE_PATH_ENABLED) &&
+  (TeamCityProperties.getBoolean(Constants.SHOW_CUSTOM_CLONE_PATH) || !StringUtil.isEmpty(propertiesBean.getProperties().get(Constants.SERVER_CLONE_PATH_PROP))) ||
+  HgVcsRoot.hasCustomClonePathWhitelist() %>"/>
 <table class="runnerFormTable">
 
   <l:settingsGroup title="General Settings">
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialPatchTestCase.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialPatchTestCase.java	Wed Jan 24 17:38:56 2018 +0100
@@ -20,10 +20,13 @@
 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
 import jetbrains.buildServer.vcs.patches.PatchTestCase;
 import org.jetbrains.annotations.NotNull;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
 
 import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.copyRepository;
 
@@ -32,11 +35,19 @@
  *         Date: 31.07.2008
  */
 public abstract class BaseMercurialPatchTestCase extends PatchTestCase {
-  @Override
+  private Set<String> myPropertiesToClean;
+
   @BeforeMethod
   protected void setUp() throws Exception {
     super.setUp();
     new TeamCityProperties() {{ setModel(new BasePropertiesModel() {});}};
+    myPropertiesToClean = new HashSet<>();
+  }
+
+  @AfterMethod
+  public void tearDown() {
+    cleanInternalProperties();
+    myTempFiles.cleanup();
   }
 
   protected VcsRootImpl createVcsRoot(@NotNull String repPath) throws IOException {
@@ -52,4 +63,16 @@
   protected String simpleRepo() {
     return new File("mercurial-tests/testData/rep1").getAbsolutePath();
   }
+
+  protected void setInternalProperty(@NotNull String propKey, @NotNull String value) {
+    System.setProperty(propKey, value);
+    myPropertiesToClean.add(propKey);
+  }
+
+  private void cleanInternalProperties() {
+    for (String prop : myPropertiesToClean) {
+      System.getProperties().remove(prop);
+    }
+    myPropertiesToClean.clear();
+  }
 }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java	Wed Jan 24 17:38:56 2018 +0100
@@ -25,20 +25,25 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
 
 import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.copyRepository;
 
 public class BaseMercurialTestCase {
   protected TempFiles myTempFiles;
+  private Set<String> myPropertiesToClean;
 
   @BeforeMethod
   public void setUp() throws Exception {
     new TeamCityProperties() {{ setModel(new BasePropertiesModel() {});}};
     myTempFiles = new TempFiles();
+    myPropertiesToClean = new HashSet<>();
   }
 
   @AfterMethod
   public void tearDown() {
+    cleanInternalProperties();
     myTempFiles.cleanup();
   }
 
@@ -49,4 +54,16 @@
     copyRepository(new File(testRepoPath), result);
     return result;
   }
+
+  protected void setInternalProperty(@NotNull String propKey, @NotNull String value) {
+    System.setProperty(propKey, value);
+    myPropertiesToClean.add(propKey);
+  }
+
+  private void cleanInternalProperties() {
+    for (String prop : myPropertiesToClean) {
+      System.getProperties().remove(prop);
+    }
+    myPropertiesToClean.clear();
+  }
 }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootFactoryTest.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootFactoryTest.java	Wed Jan 24 17:38:56 2018 +0100
@@ -35,6 +35,7 @@
 
   @TestFor(issues = "TW-25057")
   public void vcs_root_custom_clone_dir_should_not_contain_password() throws Exception {
+    setInternalProperty(Constants.CUSTOM_CLONE_PATH_ENABLED, "true");
     TempFiles tmp = new TempFiles();
     String urlWithoutPath = "http://only.host/";
     String password = "pwd";
@@ -52,6 +53,7 @@
 
   @TestFor(issues = "TW-32540")
   public void custom_clone_dir_should_contain_only_valid_characters() throws Exception {
+    setInternalProperty(Constants.CUSTOM_CLONE_PATH_ENABLED, "true");
     TempFiles tmp = new TempFiles();
     String urlWithoutPath = "http://acme:8000/";
     VcsRoot root = vcsRoot()
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootTest.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootTest.java	Wed Jan 24 17:38:56 2018 +0100
@@ -16,29 +16,22 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
-import jetbrains.buildServer.serverSide.BasePropertiesModel;
-import jetbrains.buildServer.serverSide.TeamCityProperties;
 import jetbrains.buildServer.util.TestFor;
 import jetbrains.buildServer.vcs.VcsRoot;
 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
-import junit.framework.TestCase;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import java.io.File;
 
 import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot;
+import static org.testng.Assert.*;
+import static org.testng.AssertJUnit.assertEquals;
 
 /**
  * @author Pavel.Sher
  */
 @Test
-public class HgVcsRootTest extends TestCase {
-
-  @BeforeMethod
-  public void setUp() throws Exception {
-    new TeamCityProperties() {{ setModel(new BasePropertiesModel() {});}};
-  }
+public class HgVcsRootTest extends BaseMercurialTestCase {
 
   public void test_url_without_credentials() {
     VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path");
@@ -117,19 +110,35 @@
     assertEquals("ssh://user:pwd@ourserver.com/mercurialrepo/", root.getRepositoryUrlWithCredentials());
   }
 
-  @TestFor(issues = "TW-36401")
+  @TestFor(issues = {"TW-36401", "TW-50054"})
   public void test_disabling_custom_clone_dirs() throws Exception {
     File cloneDir = new File("");
     VcsRoot root = vcsRoot().withCloneRepositoryTo(cloneDir).withUrl("http://some.org/repo").build();
     HgVcsRoot hgRoot1 = new HgVcsRoot(root);
-    assertEquals(cloneDir.getAbsolutePath(), hgRoot1.getCustomClonePath());
-    try {
-      System.setProperty(Constants.CUSTOM_CLONE_PATH_ENABLED, "false");
-      HgVcsRoot hgRoot2 = new HgVcsRoot(root);
-      assertNull(hgRoot2.getCustomClonePath());
-    } finally {
-      System.getProperties().remove(Constants.CUSTOM_CLONE_PATH_ENABLED);
-    }
+    assertNull(hgRoot1.getCustomClonePath());
+    setInternalProperty(Constants.CUSTOM_CLONE_PATH_ENABLED, "true");
+    HgVcsRoot hgRoot2 = new HgVcsRoot(root);
+    assertEquals(cloneDir.getAbsolutePath(), hgRoot2.getCustomClonePath());
+  }
+
+  @TestFor(issues = {"TW-36401", "TW-50054"})
+  public void custom_clone_path_whitelist() throws Exception {
+    assertFalse(HgVcsRoot.isAllowedCustomClonePath(null));
+    assertFalse(HgVcsRoot.isAllowedCustomClonePath("/some/path"));
+    setInternalProperty(Constants.CUSTOM_CLONE_PATH_WHITELIST, "/some/path1;/some/path2/*");
+    assertTrue(HgVcsRoot.isAllowedCustomClonePath("/some/path1"));
+    assertTrue(HgVcsRoot.isAllowedCustomClonePath("/some/path2/repo1"));
+    assertFalse(HgVcsRoot.isAllowedCustomClonePath("/some/path2/a/b/c"));
+    assertFalse(HgVcsRoot.isAllowedCustomClonePath("/other/path"));
+    assertFalse(HgVcsRoot.isAllowedCustomClonePath("/some/path21"));
+
+    File tempDir = myTempFiles.createTempDir();
+    VcsRoot root = vcsRoot().withCloneRepositoryTo(tempDir).withUrl("http://some.org/repo").build();
+    HgVcsRoot hgRoot = new HgVcsRoot(root);
+    assertNull(hgRoot.getCustomClonePath());
+    setInternalProperty(Constants.CUSTOM_CLONE_PATH_WHITELIST, tempDir.getCanonicalPath());
+    hgRoot = new HgVcsRoot(root);
+    assertEquals(hgRoot.getCustomClonePath(), tempDir.getCanonicalPath());
   }
 
   public void disable_custom_hg_path() throws Exception {
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Mon Jan 22 11:39:20 2018 +0100
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Wed Jan 24 17:38:56 2018 +0100
@@ -549,6 +549,7 @@
   }
 
   public void build_patch_using_custom_clone_path() throws IOException, VcsException {
+    setInternalProperty(Constants.CUSTOM_CLONE_PATH_ENABLED, "true");
     setName("cleanPatch1");
     VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
     File cloneDir = myTempFiles.createTempDir();