threads / patch / 25853

patch, 2 partsCreate a shared config file

Subject: [PATCH 0/2] Create a shared config file

## tl;dr

6 messages between Nov 25, 2010 and Nov 27, 2010. Diffs are folded; open one to read it.

replies: 5people: 4as markdown or json

Nathan W. Panike· Nov 27, 2010, 15:00 UTC · lore

Configuration should normally be on a per-repository or per-user basis. There are cases where it would be helpful to have a project share configuration across repositories and between developers. Normally this happens only via e-mail or IRC or by word-of-mouth. The solution implemented by these patches is to have a .gitconfig file in the toplevel of the repository.

This is not a finished implementation, as I have no tests written. Instead, this is ``one way to do it.''

Nathan W. Panike (2):
  Add support for a shared config file
  Document toplevel .gitconfig file
 Documentation/config.txt |   11 ++++++++++
 builtin/config.c         |    9 +++++++-
 config.c                 |   49 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 67 insertions(+), 2 deletions(-)
-- 
1.7.3.2.347.gd33a62
Nathan W. Panike· Nov 25, 2010, 17:21 UTC · re: Nathan W. Panike · lore

[PATCH 1/2] Add support for a shared config file

The idea is that a project develops indigenous aliases that should be shared project-wide. The only way to communicate this now is by channels outside of git--email or IRC or such. We add support for the case where a project configuration can be in .gitconfig in the top level of the repository.

Signed-off-by: Nathan W. Panike <nathan.panike@gmail.com>
---
 builtin/config.c |    9 ++++++++-
 config.c         |   49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 56 insertions(+), 2 deletions(-)
Show changes to 2 files +56 −2

builtin/config.c, config.c

diff --git a/builtin/config.c b/builtin/config.c
index ca4a0db..26c679d 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -154,7 +154,7 @@ static int get_value(const char *key_, const char *regex_)
 {
 	int ret = -1;
 	char *tl;
-	char *global = NULL, *repo_config = NULL;
+	char *global = NULL, *repo_config = NULL, *shared = NULL;
 	const char *system_wide = NULL, *local;
 
 	local = config_exclusive_filename;
@@ -165,6 +165,8 @@ static int get_value(const char *key_, const char *regex_)
 			global = xstrdup(mkpath("%s/.gitconfig", home));
 		if (git_config_system())
 			system_wide = git_etc_gitconfig();
+		if(git_config_shared())
+			shared=xstrdup(".gitconfig");
 	}
 
 	key = xstrdup(key_);
@@ -198,11 +200,15 @@ static int get_value(const char *key_, const char *regex_)
 		git_config_from_file(show_config, system_wide, NULL);
 	if (do_all && global)
 		git_config_from_file(show_config, global, NULL);
+	if (do_all && shared) 
+		git_config_from_shared_file(show_config, shared, NULL);	
 	if (do_all)
 		git_config_from_file(show_config, local, NULL);
 	git_config_from_parameters(show_config, NULL);
 	if (!do_all && !seen)
 		git_config_from_file(show_config, local, NULL);
+	if (!do_all && !seen && shared) 
+		git_config_from_shared_file(show_config, shared, NULL);	
 	if (!do_all && !seen && global)
 		git_config_from_file(show_config, global, NULL);
 	if (!do_all && !seen && system_wide)
@@ -222,6 +228,7 @@ static int get_value(const char *key_, const char *regex_)
 free_strings:
 	free(repo_config);
 	free(global);
+	free(shared);
 	return ret;
 }
 
diff --git a/config.c b/config.c
index c63d683..a9e6bec 100644
--- a/config.c
+++ b/config.c
@@ -795,6 +795,38 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
 	return ret;
 }
 
+struct config_interceptor {
+	config_fn_t fn;
+	void* data;
+};
+
+/*
+ * The purpose of this function is to keep a malicious contributor from
+ * poisoning our configuration.  The idea of a shared configuration it to
+ * pass around helpful stuff like aliases, but we do not want to allow someone
+ * to say, change our email address or the url of the remote.
+ */
+
+static int config_interceptor_fn(const char*name, const char* value, void* data)
+{
+	int ret=0;
+	struct config_interceptor *ci = (struct config_interceptor*)data;
+	if( !ci ) {
+		return -1;
+	}
+	if(!prefixcmp(name,"alias."))
+		ret = (*ci->fn)(name,value,ci->data);
+	return ret;
+}
+
+int git_config_from_shared_file(config_fn_t fn,const char* filename, void* data)
+{
+	struct config_interceptor ci;
+	ci.fn=fn;
+	ci.data=data;	
+	return git_config_from_file(config_interceptor_fn,filename,&ci);
+}
+
 const char *git_etc_gitconfig(void)
 {
 	static const char *system_wide;
@@ -819,6 +851,11 @@ int git_config_global(void)
 	return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
 }
 
+int git_config_shared(void)
+{
+	return !git_env_bool("GIT_CONFIG_NOSHARED", 0);
+}
+
 int git_config_from_parameters(config_fn_t fn, void *data)
 {
 	static int loaded_environment;
@@ -840,7 +877,8 @@ int git_config(config_fn_t fn, void *data)
 	int ret = 0, found = 0;
 	char *repo_config = NULL;
 	const char *home = NULL;
-
+	const char * shared = NULL;
+	
 	/* Setting $GIT_CONFIG makes git read _only_ the given config file. */
 	if (config_exclusive_filename)
 		return git_config_from_file(fn, config_exclusive_filename, data);
@@ -860,6 +898,15 @@ int git_config(config_fn_t fn, void *data)
 		free(user_config);
 	}
 
+	if (git_config_shared()) {
+		char *shared_config=xstrdup(".gitconfig");
+		if (!access(shared_config, R_OK)) {
+			ret += git_config_from_shared_file(fn, shared_config, data);
+			found += 1;
+		}
+		free(shared_config);
+	}
+	
 	repo_config = git_pathdup("config");
 	if (!access(repo_config, R_OK)) {
 		ret += git_config_from_file(fn, repo_config, data);
-- 
1.7.3.2.347.gd33a62
Thiago Farina· Nov 27, 2010, 16:29 UTC · re: Nathan W. Panike · lore

Re: [PATCH 1/2] Add support for a shared config file

Some minor nits (style) below.

On Thu, Nov 25, 2010 at 3:21 PM, Nathan W. Panike <nathan.panike@gmail.com> wrote:

Show 31 quoted lines
> The idea is that a project develops indigenous aliases that
> should be shared project-wide.  The only way to communicate this
> now is by channels outside of git--email or IRC or such. We add
> support for the case where a project configuration can be in
> .gitconfig in the top level of the repository.
>
> Signed-off-by: Nathan W. Panike <nathan.panike@gmail.com>
> ---
>  builtin/config.c |    9 ++++++++-
>  config.c         |   49 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 56 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/config.c b/builtin/config.c
> index ca4a0db..26c679d 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -154,7 +154,7 @@ static int get_value(const char *key_, const char *regex_)
>  {
>        int ret = -1;
>        char *tl;
> -       char *global = NULL, *repo_config = NULL;
> +       char *global = NULL, *repo_config = NULL, *shared = NULL;
>        const char *system_wide = NULL, *local;
>
>        local = config_exclusive_filename;
> @@ -165,6 +165,8 @@ static int get_value(const char *key_, const char *regex_)
>                        global = xstrdup(mkpath("%s/.gitconfig", home));
>                if (git_config_system())
>                        system_wide = git_etc_gitconfig();
> +               if(git_config_shared())
> +                       shared=xstrdup(".gitconfig");
nit: add a space before and after the =
Show 40 quoted lines
>        }
>
>        key = xstrdup(key_);
> @@ -198,11 +200,15 @@ static int get_value(const char *key_, const char *regex_)
>                git_config_from_file(show_config, system_wide, NULL);
>        if (do_all && global)
>                git_config_from_file(show_config, global, NULL);
> +       if (do_all && shared)
> +               git_config_from_shared_file(show_config, shared, NULL);
>        if (do_all)
>                git_config_from_file(show_config, local, NULL);
>        git_config_from_parameters(show_config, NULL);
>        if (!do_all && !seen)
>                git_config_from_file(show_config, local, NULL);
> +       if (!do_all && !seen && shared)
> +               git_config_from_shared_file(show_config, shared, NULL);
>        if (!do_all && !seen && global)
>                git_config_from_file(show_config, global, NULL);
>        if (!do_all && !seen && system_wide)
> @@ -222,6 +228,7 @@ static int get_value(const char *key_, const char *regex_)
>  free_strings:
>        free(repo_config);
>        free(global);
> +       free(shared);
>        return ret;
>  }
>
> diff --git a/config.c b/config.c
> index c63d683..a9e6bec 100644
> --- a/config.c
> +++ b/config.c
> @@ -795,6 +795,38 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
>        return ret;
>  }
>
> +struct config_interceptor {
> +       config_fn_t fn;
> +       void* data;
> +};
> +
Would be good to add a description about what is this structure and what is for?
Show 10 quoted lines
> +/*
> + * The purpose of this function is to keep a malicious contributor from
> + * poisoning our configuration.  The idea of a shared configuration it to
> + * pass around helpful stuff like aliases, but we do not want to allow someone
> + * to say, change our email address or the url of the remote.
> + */
> +
> +static int config_interceptor_fn(const char*name, const char* value, void* data)
> +{
> +       int ret=0;
nit: add space before and after the =
> +       struct config_interceptor *ci = (struct config_interceptor*)data;
> +       if( !ci ) {
wrong, wrong.
I think the style used here is:
if (!ci) {
So, add a space after the if, and no spaces in the () please.
> +               return -1;
> +       }
> +       if(!prefixcmp(name,"alias."))
same thing here about the space after the if
Show 8 quoted lines
> +               ret = (*ci->fn)(name,value,ci->data);
> +       return ret;
> +}
> +
> +int git_config_from_shared_file(config_fn_t fn,const char* filename, void* data)
> +{
> +       struct config_interceptor ci;
> +       ci.fn=fn;
nit: fix this too and the other occurrences below.
Nathan W. Panike· Nov 25, 2010, 20:01 UTC · re: Nathan W. Panike · lore

[PATCH 2/2] Document toplevel gitconfig file

Try to explain its security implications and how to turn it off.
Signed-off-by: Nathan W. Panike <nathan.panike@gmail.com>
---
 Documentation/config.txt |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)
Show changes to Documentation/config.txt +11 −0
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6a6c0b5..6ec9a0b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -8,6 +8,17 @@ is used to store the configuration for that repository, and
 fallback values for the `.git/config` file. The file `/etc/gitconfig`
 can be used to store a system-wide default configuration.
 
+One can also create a `.gitconfig` file in the toplevel of the
+repository. This config file will then be propogated to collaborators
+when they pull from your repository.  Only `alias` config variables are
+allowed to be set in this `.gitconfig` file.  One can turn off the
+shared `.gitconfig` by setting the environment variable
+'GIT_CONFIG_NOSHARED' to 1; it will then be propogated but will not be
+used for configuration settings.  Note that this is a security issue
+because you are basically allowing someone else to dictate your
+configuration, but should be fine if you pay attention and do not use
+aliases from someone else blindly.
+
 The configuration variables are used by both the git plumbing
 and the porcelains. The variables are divided into sections, wherein
 the fully qualified variable name of the variable itself is the last
-- 
1.7.3.2.347.gd33a62
Jonathan Nieder· Nov 27, 2010, 15:52 UTC · re: Nathan W. Panike · lore

Re: [PATCH 2/2] Document toplevel gitconfig file

Nathan W. Panike wrote:
Show 13 quoted lines
> --- a/Documentation/config.txt
> +++ b/Documentation/config.txt
> @@ -8,6 +8,17 @@ is used to store the configuration for that repository, and
>  fallback values for the `.git/config` file. The file `/etc/gitconfig`
>  can be used to store a system-wide default configuration.
>  
> +One can also create a `.gitconfig` file in the toplevel of the
> +repository. This config file will then be propogated to collaborators
> +when they pull from your repository.  Only `alias` config variables are
> +allowed to be set in this `.gitconfig` file.  One can turn off the
> +shared `.gitconfig` by setting the environment variable
> +'GIT_CONFIG_NOSHARED' to 1; it will then be propogated but will not be
> +used for configuration settings.

Please no. Why not set up aliases in a setup-aliases.sh script and mention it in your README?

If I clone a repository to investigate it and then a typo results in
	$ git lgo
emptying my $HOME directory, I would not call that a feature.
Nguyen Thai Ngoc Duy· Nov 27, 2010, 16:04 UTC · re: Nathan W. Panike · lore

Re: [PATCH 0/2] Create a shared config file

On Sat, Nov 27, 2010 at 10:00 PM, Nathan W. Panike <nathan.panike@gmail.com> wrote:

Show 5 quoted lines
> Configuration should normally be on a per-repository or per-user basis.  There
> are cases where it would be helpful to have a project share configuration
> across repositories and between developers.  Normally this happens only via
> e-mail or IRC or by word-of-mouth.  The solution implemented by these patches
> is to have a .gitconfig file in the toplevel of the repository.

Or save the shared config in the repository and add an instruction in $GIT_DIR/config to include such config blob. We can worry less about malicious config that way. If you are extremely nervous about it, you can always point to a specific blob that you have checked.

-- 
Duy

← back to recent threads