Merge branch 'stable-2.14'

* stable-2.14:
  Update bazlets to latest revision on stable-2.14 to use 2.14.8 API
  Configure allowed SSH commands

Change-Id: I2ec180402413f24f9b6cda97d18bf2e795afef58
diff --git a/src/main/java/com/googlesource/gerrit/plugins/readonly/DisableCommandInterceptor.java b/src/main/java/com/googlesource/gerrit/plugins/readonly/DisableCommandInterceptor.java
index 7fec1aa..7bab398 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/readonly/DisableCommandInterceptor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/readonly/DisableCommandInterceptor.java
@@ -18,6 +18,8 @@
 import com.google.gerrit.sshd.SshCreateCommandInterceptor;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.regex.Pattern;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,17 +30,26 @@
   private static final String PATTERN = "^gerrit plugin (\\brm\\b|\\bremove\\b) %s$";
 
   private final String disableCommand;
-  private final Pattern pattern;
+  private final List<Pattern> allowPatterns = new ArrayList<>();
+  private final List<String> allowPrefixes = new ArrayList<>();
 
   @Inject
-  DisableCommandInterceptor(@PluginName String pluginName) {
+  DisableCommandInterceptor(@PluginName String pluginName, ReadOnlyConfig config) {
     this.disableCommand = pluginName + " disable";
-    this.pattern = Pattern.compile(String.format(PATTERN, pluginName));
+    allowPatterns.add(Pattern.compile(String.format(PATTERN, pluginName)));
+    for (String allow : config.allowSshCommands()) {
+      if (allow.startsWith("^")) {
+        allowPatterns.add(Pattern.compile(allow));
+      } else {
+        allowPrefixes.add(allow);
+      }
+    }
   }
 
   @Override
   public String intercept(String in) {
-    if (pattern.matcher(in).matches()) {
+    if (allowPrefixes.stream().anyMatch(p -> in.startsWith(p))
+        || allowPatterns.stream().anyMatch(p -> p.matcher(in).matches())) {
       return in;
     }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnlyConfig.java b/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnlyConfig.java
index 718a894..ba87301 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnlyConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnlyConfig.java
@@ -16,10 +16,12 @@
 
 import static com.google.common.base.MoreObjects.firstNonNull;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.util.List;
 import org.eclipse.jgit.lib.Config;
 
 @Singleton
@@ -27,16 +29,23 @@
   private static final String MESSAGE_KEY = "message";
   private static final String DEFAULT_MESSAGE =
       "Gerrit is under maintenance - all data is READ ONLY";
+  private static final String SSH_ALLOW = "allowSshCommand";
 
   private final String message;
+  private final List<String> allowSshCommands;
 
   @Inject
   ReadOnlyConfig(PluginConfigFactory pluginConfigFactory, @PluginName String pluginName) {
     Config cfg = pluginConfigFactory.getGlobalPluginConfig(pluginName);
     this.message = firstNonNull(cfg.getString(pluginName, null, MESSAGE_KEY), DEFAULT_MESSAGE);
+    allowSshCommands = ImmutableList.copyOf(cfg.getStringList(pluginName, null, SSH_ALLOW));
   }
 
   String message() {
     return message;
   }
+
+  List<String> allowSshCommands() {
+    return allowSshCommands;
+  }
 }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 883a5c5..2c3cb50 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -19,3 +19,10 @@
 :   Message to be shown to clients when attempting to perform an opeation that
     is blocked due to the server being in read-only mode. When not specified,
     the default is "Gerrit is under maintenance - all data is READ ONLY".
+
+```readonly.allowSshCommand```
+:   Allow one or more SSH commands to be executed. When the allow value starts
+    with a caret '^' then it is interpreted as regex, otherwise as a prefix.
+    Repeat with multiple values to allow more than one command or pattern
+    of commands.
+    The command 'gerrit plugin rm' or 'gerrit plugin remove' is always allowed.