Commit 1b32908973d687e4526079eeecdb82d9cb13c6e6

Patrick Steinhardt 2017-05-31T22:27:19

config_file: refuse modifying included variables Modifying variables pulled in by an included file currently succeeds, but it doesn't actually do what one would expect, as refreshing the configuration will cause the values to reappear. As we are currently not really able to support this use case, we will instead just return an error for deleting and setting variables which were included via an include.

diff --git a/src/config_file.c b/src/config_file.c
index 3a1a32d..8ac89b3 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -490,6 +490,12 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
 			goto out;
 		}
 
+		if (existing->included) {
+			giterr_set(GITERR_CONFIG, "modifying included variable is not supported");
+			ret = -1;
+			goto out;
+		}
+
 		/* don't update if old and new values already match */
 		if ((!existing->entry->value && !value) ||
 			(existing->entry->value && value &&
@@ -624,6 +630,11 @@ static int config_delete(git_config_backend *cfg, const char *name)
 	var = git_strmap_value_at(values, pos);
 	refcounted_strmap_free(map);
 
+	if (var->included) {
+		giterr_set(GITERR_CONFIG, "cannot delete included variable");
+		return -1;
+	}
+
 	if (var->next != NULL) {
 		giterr_set(GITERR_CONFIG, "cannot delete multivar with a single delete");
 		return -1;
diff --git a/tests/config/include.c b/tests/config/include.c
index bcf8e19..e440b9a 100644
--- a/tests/config/include.c
+++ b/tests/config/include.c
@@ -146,3 +146,21 @@ void test_config_include__rewriting_include_refreshes_values(void)
 	cl_git_pass(git_config_get_string_buf(&buf, cfg, "first.other"));
 	cl_assert_equal_s(buf.ptr, "value");
 }
+
+void test_config_include__included_variables_cannot_be_deleted(void)
+{
+	cl_git_mkfile("top-level", "[include]\npath = included\n");
+	cl_git_mkfile("included", "[foo]\nbar = value");
+
+	cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+	cl_git_fail(git_config_delete_entry(cfg, "foo.bar"));
+}
+
+void test_config_include__included_variables_cannot_be_modified(void)
+{
+	cl_git_mkfile("top-level", "[include]\npath = included\n");
+	cl_git_mkfile("included", "[foo]\nbar = value");
+
+	cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+	cl_git_fail(git_config_set_string(cfg, "foo.bar", "other-value"));
+}