Repository: gocd/gocd
Issue: Test Drive/standalone GoCD fails to start when commit GPG signing is enabled at system/user level

##### Issue Type

- Bug Report

##### Summary
When I run Test Drive 21.4.0 (`gocd-21.4.0-13469-1477-osx`) which is current stable version, GoCD server couldn't be started.

##### Environment

On my macbook

###### Basic environment details

* Go Version: `21.4.0`
* JAVA Version: `openjdk 15.0.4`
* OS: `macOS 11.6`

##### Steps to Reproduce

1. Run `curl -fsSL 'https://www.gocd.org/test-drive-gocd/try.sh' | bash -s 'https://download.gocd.org/test-drive/installers/21.4.0/13469/gocd-21.4.0-13469-1477-osx.zip'` 
2. Server hung with `Wating for the GoCD server to finish initializing.....`

##### Expected Results
GoCD Server launched

##### Actual Results
Starting server failed.

##### Log snippets
```
org.eclipse.jgit.api.errors.ServiceUnavailableException: Signing service is not available
	at org.eclipse.jgit.api.CommitCommand.sign(CommitCommand.java:290)
	at org.eclipse.jgit.api.CommitCommand.call(CommitCommand.java:247)
	at com.thoughtworks.go.service.ConfigRepository$1.run(ConfigRepository.java:125)
	at com.thoughtworks.go.util.VoidThrowingFn.call(VoidThrowingFn.java:25)
	at com.thoughtworks.go.service.ConfigRepository.doLocked(ConfigRepository.java:136)
	at com.thoughtworks.go.service.ConfigRepository.checkin(ConfigRepository.java:121)
	at com.thoughtworks.go.config.FullConfigSaveFlow.checkinToConfigRepo(FullConfigSaveFlow.java:79)
	at com.thoughtworks.go.config.FullConfigSaveNormalFlow.execute(FullConfigSaveNormalFlow.java:67)
	at com.thoughtworks.go.config.GoConfigMigrator.upgradeConfigFile(GoConfigMigrator.java:110)
	at com.thoughtworks.go.config.GoConfigMigrator.upgrade(GoConfigMigrator.java:96)
	at com.thoughtworks.go.config.GoConfigMigrator.migrate(GoConfigMigrator.java:87)
	at com.thoughtworks.go.config.CachedGoConfig.upgradeConfig(CachedGoConfig.java:149)
	at com.thoughtworks.go.server.initializers.ApplicationInitializer.onApplicationEvent(ApplicationInitializer.java:112)
	at com.thoughtworks.go.server.initializers.ApplicationInitializer.onApplicationEvent(ApplicationInitializer.java:49)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)
	at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443)
	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325)
	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
	at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:1067)
	at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:572)
	at org.eclipse.jetty.server.handler.ContextHandler.contextInitialized(ContextHandler.java:996)
	at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:746)
	at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:379)
	at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1449)
	at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1414)
	at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:910)
	at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:288)
	at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:524)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
	at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:46)
	at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:188)
	at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:517)
	at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:157)
	at com.thoughtworks.go.server.Jetty9Server.startHandlers(Jetty9Server.java:179)
	at com.thoughtworks.go.server.Jetty9Server.start(Jetty9Server.java:129)
	at com.thoughtworks.go.server.GoServer.startServer(GoServer.java:62)
	at com.thoughtworks.go.server.GoServer.go(GoServer.java:54)
	at com.thoughtworks.go.server.util.GoLauncher.main(GoLauncher.java:42)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at com.thoughtworks.gocd.Boot.run(Boot.java:90)
	at com.thoughtworks.gocd.Boot.main(Boot.java:56)
2022-01-14 20:54:16,934 WARN  [main] GoConfigMigrator:98 - Error upgrading config file, trying to upgrade using the versioned config file.
2022-01-14 20:54:16,935 WARN  [main] ConfigRepository:196 - [CONFIG REPOSITORY] No head exists in the config repository.
2022-01-14 20:54:16,935 WARN  [main] GoConfigMigrator:116 - There is no versioned configuration to fallback for migration.
2022-01-14 20:54:16,944 ERROR [main] GoConfigMigrator:64 - There are errors in the Cruise config file.  Please read the error message and correct the errors.
Once fixed, please restart GoCD.
Error: Signing service is not available
```


Changed files:
config/config-server/src/main/java/com/thoughtworks/go/service/ConfigRepository.java
config/config-server/src/test/java/com/thoughtworks/go/service/ConfigRepositoryTest.java

diff --git a/config/config-server/src/main/java/com/thoughtworks/go/service/ConfigRepository.java b/config/config-server/src/main/java/com/thoughtworks/go/service/ConfigRepository.java
index 8eb6f587f3..9f2520ca6b 100644
--- a/config/config-server/src/main/java/com/thoughtworks/go/service/ConfigRepository.java
+++ b/config/config-server/src/main/java/com/thoughtworks/go/service/ConfigRepository.java
@@ -78,10 +78,14 @@ public class ConfigRepository {
         workingDir = this.systemEnvironment.getConfigRepoDir();
         File configRepoDir = new File(workingDir, ".git");
         gitRepo = new FileRepositoryBuilder().setGitDir(configRepoDir).build();
-        gitRepo.getConfig().setInt("gc", null, "auto", 0);
+        updateWithDefaults(gitRepo.getConfig());
         git = new Git(gitRepo);
     }
 
+    private void updateWithDefaults(StoredConfig config) {
+        config.setInt(ConfigConstants.CONFIG_GC_SECTION, null, ConfigConstants.CONFIG_KEY_AUTO, 0);
+        config.setBoolean(ConfigConstants.CONFIG_COMMIT_SECTION, null, ConfigConstants.CONFIG_KEY_GPGSIGN, false);
+    }
 
     public Repository getGitRepo() {
         return gitRepo;
diff --git a/config/config-server/src/test/java/com/thoughtworks/go/service/ConfigRepositoryTest.java b/config/config-server/src/test/java/com/thoughtworks/go/service/ConfigRepositoryTest.java
index 25fbac99ae..b40abe1b64 100644
--- a/config/config-server/src/test/java/com/thoughtworks/go/service/ConfigRepositoryTest.java
+++ b/config/config-server/src/test/java/com/thoughtworks/go/service/ConfigRepositoryTest.java
@@ -24,8 +24,11 @@ import com.thoughtworks.go.util.SystemEnvironment;
 import com.thoughtworks.go.util.TimeProvider;
 import org.eclipse.jgit.api.ListBranchCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.SystemReader;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -35,6 +38,7 @@ import java.io.File;
 import java.io.IOException;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Consumer;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
@@ -70,6 +74,33 @@ public class ConfigRepositoryTest {
         assertThat(configRepo.getRevision("md5-v2").getContent(), is("v1 v2"));
     }
 
+    @Test
+    public void shouldBeAbleToCheckInWithGlobalGpgSigningEnabled() throws Exception {
+        try (UndoableUserGitConfig ignored = new UndoableUserGitConfig(c -> c.setBoolean(ConfigConstants.CONFIG_COMMIT_SECTION, null, ConfigConstants.CONFIG_KEY_GPGSIGN, true))) {
+            configRepo = new ConfigRepository(systemEnvironment);
+            configRepo.initialize();
+            configRepo.checkin(new GoConfigRevision("v1", "md5-v1", "user-name", "100.3.9", new TimeProvider()));
+            assertThat(configRepo.getRevision("md5-v1").getContent(), is("v1"));
+            assertThat(configRepo.getCurrentRevCommit().getRawGpgSignature(), nullValue());
+        }
+    }
+
+    private static class UndoableUserGitConfig implements AutoCloseable {
+        private final String originalConfig;
+
+        public UndoableUserGitConfig(Consumer<StoredConfig> configConsumer) throws Exception {
+            StoredConfig config = SystemReader.getInstance().getUserConfig();
+            originalConfig = config.toText();
+            configConsumer.accept(config);
+        }
+
+        @Override
+        public void close() throws Exception {
+            StoredConfig config = SystemReader.getInstance().getUserConfig();
+            config.fromText(originalConfig);
+        }
+    }
+
     @Test
     public void shouldGetCommitsCorrectly() throws Exception {
         configRepo.checkin(new GoConfigRevision("v1", "md5-v1", "user-name", "100.3.9", new TimeProvider()));
@@ -110,7 +141,7 @@ public class ConfigRepositoryTest {
     }
 
     @Test
-    public void shouldReturnNullWhenThereAreNoCheckIns() throws GitAPIException, IOException {
+    public void shouldReturnNullWhenThereAreNoCheckIns() throws Exception {
         assertThat(configRepo.getRevision("current"), is(nullValue()));
     }
 
@@ -317,7 +348,7 @@ public class ConfigRepositoryTest {
     }
 
     @Test
-    public void shouldSwitchToMasterAndDeleteTempBranches() throws Exception, GitAPIException {
+    public void shouldSwitchToMasterAndDeleteTempBranches() throws Exception {
         configRepo.checkin(goConfigRevision("v1", "md5-1"));
         configRepo.createBranch(ConfigRepository.BRANCH_AT_HEAD, configRepo.getCurrentRevCommit());
         configRepo.createBranch(ConfigRepository.BRANCH_AT_REVISION, configRepo.getCurrentRevCommit());
@@ -376,10 +407,10 @@ public class ConfigRepositoryTest {
     public void shouldPerformGC() throws Exception {
         configRepo.checkin(goConfigRevision("v1", "md5-1"));
         Long numberOfLooseObjects = (Long) configRepo.git().gc().getStatistics().get("sizeOfLooseObjects");
-        assertThat(numberOfLooseObjects > 0l, is(true));
+        assertThat(numberOfLooseObjects > 0L, is(true));
         configRepo.garbageCollect();
         numberOfLooseObjects = (Long) configRepo.git().gc().getStatistics().get("sizeOfLooseObjects");
-        assertThat(numberOfLooseObjects, is(0l));
+        assertThat(numberOfLooseObjects, is(0L));
     }
 
     @Test
@@ -411,7 +442,7 @@ public class ConfigRepositoryTest {
         return new GoConfigRevision(fileContent, md5, "user-1", "13.2", new TimeProvider());
     }
 
-    private String getLatestConfigAt(String branchName) throws GitAPIException, IOException {
+    private String getLatestConfigAt(String branchName) throws GitAPIException {
         configRepo.git().checkout().setName(branchName).call();
 
         String content = configRepo.getCurrentRevision().getContent();