repo: Ensure new config doesn't set remotes in separate file
authorDan Nicholson <nicholson@endlessm.com>
Mon, 11 Sep 2017 17:57:42 +0000 (12:57 -0500)
committerAtomic Bot <atomic-devel@projectatomic.io>
Wed, 13 Sep 2017 16:03:25 +0000 (16:03 +0000)
If the new configuration passed to ostree_write_config () tries to
update options for a remote defined in a separate config file, return an
error. Without this, the full configuration would contain duplicate
remote specifications, which would raise an error the next time the repo
is opened.

Closes: #1159
Approved by: cgwalters

src/libostree/ostree-repo.c
tests/test-remotes-config-dir.js

index b529854e8074dbaa363d091aa070b3afac7d7b38..3d56bb55a71d9350d4dd139c36338bd5a991c05b 100644 (file)
@@ -933,6 +933,40 @@ ostree_repo_write_config (OstreeRepo *self,
 {
   g_return_val_if_fail (self->inited, FALSE);
 
+  /* Ensure that any remotes in the new config aren't defined in a
+   * separate config file.
+   */
+  gsize num_groups;
+  g_auto(GStrv) groups = g_key_file_get_groups (new_config, &num_groups);
+  for (gsize i = 0; i < num_groups; i++)
+    {
+      g_autoptr(OstreeRemote) new_remote = ostree_remote_new_from_keyfile (new_config, groups[i]);
+      if (new_remote != NULL)
+        {
+          g_autoptr(GError) local_error = NULL;
+
+          g_autoptr(OstreeRemote) cur_remote =
+            _ostree_repo_get_remote (self, new_remote->name, &local_error);
+          if (cur_remote == NULL)
+            {
+              if (!g_error_matches (local_error, G_IO_ERROR,
+                                    G_IO_ERROR_NOT_FOUND))
+                {
+                  g_propagate_error (error, g_steal_pointer (&local_error));
+                  return FALSE;
+                }
+            }
+          else if (cur_remote->file != NULL)
+            {
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
+                           "Remote \"%s\" already defined in %s",
+                           new_remote->name,
+                           gs_file_get_path_cached (cur_remote->file));
+              return FALSE;
+            }
+        }
+    }
+
   gsize len;
   g_autofree char *data = g_key_file_to_data (new_config, &len, error);
   if (!glnx_file_replace_contents_at (self->repo_dir_fd, "config",
index 11d773489d6903200e8e43e3ee17b30564246c3a..7b6585c9862b6e63592751d500cd85756da9f89c 100755 (executable)
@@ -32,7 +32,7 @@ function assertNotEquals(a, b) {
        throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b));
 }
 
-print('1..4')
+print('1..6')
 
 let remotesDir = Gio.File.new_for_path('remotes.d');
 remotesDir.make_directory(null);
@@ -85,3 +85,30 @@ assertNotEquals(remotes.indexOf('baz'), -1);
 assertEquals(remotesDir.get_child('baz.conf').query_exists(null), true);
 
 print("ok add-in-remotes-config-dir");
+
+// Trying to set a remote config option via write_config() for a remote
+// defined in the config file should succeed
+let [, gpg_verify] = repo.remote_get_gpg_verify('bar');
+assertEquals(gpg_verify, true);
+repoConfig = repo.copy_config();
+repoConfig.set_boolean('remote "bar"', 'gpg-verify', false);
+repo.write_config(repoConfig);
+repo.reload_config(null);
+[, gpg_verify] = repo.remote_get_gpg_verify('bar');
+assertEquals(gpg_verify, false);
+
+print("ok config-remote-in-config-file-succeeds");
+
+// Trying to set a remote config option via write_config() for a remote
+// defined in the config dir should fail with G_IO_ERROR_EXISTS
+repoConfig = repo.copy_config();
+repoConfig.set_boolean('remote "baz"', 'gpg-verify', false);
+try {
+    if (repo.write_config(repoConfig))
+        throw new Error("config of remote in config dir should fail");
+} catch (e) {
+    if (!(e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)))
+        throw e;
+}
+
+print("ok config-remote-in-config-dir-fails");