Merge branch 'stable-3.9'

* stable-3.9:
  Invalidate service user cache each time All-Projects is updated
  Fix missing group add of serviceuser for ssh register command

Bug: Issue 372736304
Bug: Issue 367623920
Change-Id: I13a1b29290632f6433659b62ff1bcdbd3aa3055a
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
index c3b5add..a4ced57 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
@@ -39,8 +39,8 @@
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.VersionedConfigFile;
 import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.gerrit.server.restapi.account.CreateAccount;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -75,7 +75,7 @@
   }
 
   private final PluginConfig cfg;
-  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final Provider<VersionedConfigFile> configProvider;
   private final CreateAccount createAccount;
   private final Provider<CurrentUser> userProvider;
   private final MetaDataUpdate.User metaDataUpdateFactory;
@@ -89,7 +89,7 @@
   @Inject
   CreateServiceUser(
       PluginConfigFactory cfgFactory,
-      Provider<ProjectLevelConfig.Bare> configProvider,
+      Provider<VersionedConfigFile> configProvider,
       @PluginName String pluginName,
       CreateAccount createAccount,
       Provider<CurrentUser> userProvider,
@@ -132,11 +132,7 @@
       throw new BadRequestException("username must match URL");
     }
 
-    if (Strings.isNullOrEmpty(input.sshKey)) {
-      throw new BadRequestException("sshKey not set");
-    }
-
-    if (!SshKeyValidator.validateFormat(input.sshKey)) {
+    if (input.sshKey != null && !SshKeyValidator.validateFormat(input.sshKey)) {
       throw new BadRequestException("sshKey invalid.");
     }
 
@@ -173,7 +169,7 @@
     String creationDate = rfc2822DateFormatter.format(new Date());
 
     try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjects)) {
-      ProjectLevelConfig.Bare update = configProvider.get();
+      VersionedConfigFile update = configProvider.get();
       update.load(md);
 
       Config db = update.getConfig();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
index 3f27975..4ee88ee 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
@@ -40,7 +40,7 @@
 
   @Option(
       name = "--ssh-key",
-      required = true,
+      required = false,
       metaVar = "-|KEY",
       usage = "public key for SSH authentication")
   private String sshKey;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
index 39d5788..1baa0ee 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
@@ -27,8 +27,8 @@
 import com.google.gerrit.extensions.restapi.RestApiModule;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.gerrit.server.events.EventListener;
+import com.google.gerrit.server.git.meta.VersionedConfigFile;
 import com.google.gerrit.server.git.validators.CommitValidationListener;
-import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.assistedinject.FactoryModuleBuilder;
@@ -82,7 +82,7 @@
   }
 
   @Provides
-  ProjectLevelConfig.Bare createProjectLevelConfig(@PluginName String pluginName) {
-    return new ProjectLevelConfig.Bare(pluginName + ".db");
+  VersionedConfigFile createProjectLevelConfig(@PluginName String pluginName) {
+    return new VersionedConfigFile(pluginName + ".db");
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
index 32ee082..e3af6a0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
@@ -35,10 +35,10 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.VersionedConfigFile;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.gerrit.server.restapi.group.GroupJson;
 import com.google.gerrit.server.restapi.group.GroupsCollection;
 import com.google.inject.Inject;
@@ -57,7 +57,7 @@
 
   private final Provider<GetConfig> getConfig;
   private final GroupsCollection groups;
-  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final Provider<VersionedConfigFile> configProvider;
   private final Project.NameKey allProjects;
   private final MetaDataUpdate.User metaDataUpdateFactory;
   private final GroupJson json;
@@ -69,7 +69,7 @@
   PutOwner(
       Provider<GetConfig> getConfig,
       GroupsCollection groups,
-      Provider<ProjectLevelConfig.Bare> configProvider,
+      Provider<VersionedConfigFile> configProvider,
       ProjectCache projectCache,
       MetaDataUpdate.User metaDataUpdateFactory,
       GroupJson json,
@@ -107,7 +107,7 @@
     GroupDescription.Basic group = null;
     String oldGroup;
     try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjects)) {
-      ProjectLevelConfig.Bare update = configProvider.get();
+      VersionedConfigFile update = configProvider.get();
       update.load(md);
 
       Config db = update.getConfig();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RegisterServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RegisterServiceUser.java
index e8b6e3e..0d36a5e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RegisterServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RegisterServiceUser.java
@@ -50,12 +50,12 @@
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.VersionedConfigFile;
 import com.google.gerrit.server.group.GroupResolver;
 import com.google.gerrit.server.group.db.GroupDelta;
 import com.google.gerrit.server.group.db.GroupsUpdate;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -82,7 +82,7 @@
     String owner;
   }
 
-  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final Provider<VersionedConfigFile> configProvider;
   private final AccountResolver accountResolver;
   private final GroupResolver groupResolver;
   private final Provider<CurrentUser> userProvider;
@@ -99,7 +99,7 @@
 
   @Inject
   RegisterServiceUser(
-      Provider<ProjectLevelConfig.Bare> configProvider,
+      Provider<VersionedConfigFile> configProvider,
       AccountResolver accountResolver,
       GroupResolver groupResolver,
       Provider<CurrentUser> userProvider,
@@ -181,7 +181,7 @@
     }
 
     try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjects)) {
-      ProjectLevelConfig.Bare update = configProvider.get();
+      VersionedConfigFile update = configProvider.get();
       update.load(md);
 
       Config db = update.getConfig();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshModule.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshModule.java
index 40a1509..85b1e88 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshModule.java
@@ -14,9 +14,15 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.sshd.PluginCommandModule;
+import com.google.inject.Inject;
 
 class SshModule extends PluginCommandModule {
+  @Inject
+  SshModule(@PluginName String pluginName) {
+    super(pluginName);
+  }
 
   @Override
   protected void configureCommands() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/StorageCache.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/StorageCache.java
index 0378347..d77c569 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/StorageCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/StorageCache.java
@@ -20,8 +20,7 @@
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.project.ProjectLevelConfig;
-import com.google.gerrit.server.project.ProjectLevelConfig.Bare;
+import com.google.gerrit.server.git.meta.VersionedConfigFile;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -67,13 +66,13 @@
   }
 
   static class Loader extends CacheLoader<Object, Config> {
-    private final Provider<Bare> configProvider;
+    private final Provider<VersionedConfigFile> configProvider;
     private final MetaDataUpdate.Server metaDataUpdateFactory;
     private final AllProjectsName allProjects;
 
     @Inject
     Loader(
-        Provider<ProjectLevelConfig.Bare> configProvider,
+        Provider<VersionedConfigFile> configProvider,
         MetaDataUpdate.Server metaDataUpdateFactory,
         AllProjectsName allProjects) {
       this.configProvider = configProvider;
@@ -83,7 +82,7 @@
 
     @Override
     public Config load(Object key) throws Exception {
-      ProjectLevelConfig.Bare storage = configProvider.get();
+      VersionedConfigFile storage = configProvider.get();
       try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjects)) {
         storage.load(md);
       }
diff --git a/web/gr-serviceuser-create.ts b/web/gr-serviceuser-create.ts
index 3ee2a70..eaf864b 100644
--- a/web/gr-serviceuser-create.ts
+++ b/web/gr-serviceuser-create.ts
@@ -58,9 +58,6 @@
   @query('#serviceUserEmailInput')
   serviceUserEmailInput!: HTMLInputElement;
 
-  @query('#serviceUserKeyInput')
-  serviceUserKeyInput!: HTMLInputElement;
-
   @property()
   plugin!: PluginApi;
 
@@ -94,9 +91,6 @@
   @property({type: String})
   email?: String;
 
-  @property({type: String})
-  key?: String;
-
   @property({type: Object})
   accountId?: AccountId;
 
@@ -141,20 +135,6 @@
           </section>
           ${this.renderEmailInputSection()}
         </fieldset>
-        <fieldset>
-          <section>
-            <span class="title">Public SSH key</span>
-            <span class="value">
-              <iron-autogrow-textarea
-                id="serviceUserKeyInput"
-                .bind-value="${this.key}"
-                placeholder="New SSH Key"
-                @bind-value-changed=${this.validateData}
-              >
-              </iron-autogrow-textarea>
-            </span>
-          </section>
-        </fieldset>
         <gr-button
           id="createButton"
           @click=${this.handleCreateServiceUser}
@@ -253,8 +233,7 @@
   private validateData() {
     this.dataValid =
       this.validateName(this.serviceUserNameInput.value) &&
-      this.validateEmail(this.serviceUserEmailInput?.value) &&
-      this.validateKey(this.serviceUserKeyInput.value);
+      this.validateEmail(this.serviceUserEmailInput?.value);
   }
 
   private validateName(username: String | undefined) {
@@ -275,19 +254,9 @@
     return false;
   }
 
-  private validateKey(key: String | undefined) {
-    if (!key?.trim()) {
-      return false;
-    }
-
-    this.key = key;
-    return true;
-  }
-
   private handleCreateServiceUser() {
     this.isAdding = true;
     const body: ServiceUserInput = {
-      ssh_key: this.key ? this.key.trim() : '',
       email: this.email ? this.email.trim() : '',
     };
     return this.plugin