Skip to content

Commit 14111fc

Browse files
jacob-kellergitster
authored andcommitted
git: submodule honor -c credential.* from command line
Due to the way that the git-submodule code works, it clears all local git environment variables before entering submodules. This is normally a good thing since we want to clear settings such as GIT_WORKTREE and other variables which would affect the operation of submodule commands. However, GIT_CONFIG_PARAMETERS is special, and we actually do want to preserve these settings. However, we do not want to preserve all configuration as many things should be left specific to the parent project. Add a git submodule--helper function, sanitize-config, which shall be used to sanitize GIT_CONFIG_PARAMETERS, removing all key/value pairs except a small subset that are known to be safe and necessary. Replace all the calls to clear_local_git_env with a wrapped function that filters GIT_CONFIG_PARAMETERS using the new helper and then restores it to the filtered subset after clearing the rest of the environment. Signed-off-by: Jacob Keller <jacob.keller@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent e70986d commit 14111fc

File tree

4 files changed

+133
-14
lines changed

4 files changed

+133
-14
lines changed

builtin/submodule--helper.c

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,55 @@ static int module_name(int argc, const char **argv, const char *prefix)
124124

125125
return 0;
126126
}
127+
128+
/*
129+
* Rules to sanitize configuration variables that are Ok to be passed into
130+
* submodule operations from the parent project using "-c". Should only
131+
* include keys which are both (a) safe and (b) necessary for proper
132+
* operation.
133+
*/
134+
static int submodule_config_ok(const char *var)
135+
{
136+
if (starts_with(var, "credential."))
137+
return 1;
138+
return 0;
139+
}
140+
141+
static int sanitize_submodule_config(const char *var, const char *value, void *data)
142+
{
143+
struct strbuf *out = data;
144+
145+
if (submodule_config_ok(var)) {
146+
if (out->len)
147+
strbuf_addch(out, ' ');
148+
149+
if (value)
150+
sq_quotef(out, "%s=%s", var, value);
151+
else
152+
sq_quote_buf(out, var);
153+
}
154+
155+
return 0;
156+
}
157+
158+
static void prepare_submodule_repo_env(struct argv_array *out)
159+
{
160+
const char * const *var;
161+
162+
for (var = local_repo_env; *var; var++) {
163+
if (!strcmp(*var, CONFIG_DATA_ENVIRONMENT)) {
164+
struct strbuf sanitized_config = STRBUF_INIT;
165+
git_config_from_parameters(sanitize_submodule_config,
166+
&sanitized_config);
167+
argv_array_pushf(out, "%s=%s", *var, sanitized_config.buf);
168+
strbuf_release(&sanitized_config);
169+
} else {
170+
argv_array_push(out, *var);
171+
}
172+
}
173+
174+
}
175+
127176
static int clone_submodule(const char *path, const char *gitdir, const char *url,
128177
const char *depth, const char *reference, int quiet)
129178
{
@@ -145,7 +194,7 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url
145194
argv_array_push(&cp.args, path);
146195

147196
cp.git_cmd = 1;
148-
cp.env = local_repo_env;
197+
prepare_submodule_repo_env(&cp.env_array);
149198
cp.no_stdin = 1;
150199

151200
return run_command(&cp);
@@ -259,6 +308,22 @@ static int module_clone(int argc, const char **argv, const char *prefix)
259308
return 0;
260309
}
261310

311+
static int module_sanitize_config(int argc, const char **argv, const char *prefix)
312+
{
313+
struct strbuf sanitized_config = STRBUF_INIT;
314+
315+
if (argc > 1)
316+
usage(_("git submodule--helper sanitize-config"));
317+
318+
git_config_from_parameters(sanitize_submodule_config, &sanitized_config);
319+
if (sanitized_config.len)
320+
printf("%s\n", sanitized_config.buf);
321+
322+
strbuf_release(&sanitized_config);
323+
324+
return 0;
325+
}
326+
262327
struct cmd_struct {
263328
const char *cmd;
264329
int (*fn)(int, const char **, const char *);
@@ -268,6 +333,7 @@ static struct cmd_struct commands[] = {
268333
{"list", module_list},
269334
{"name", module_name},
270335
{"clone", module_clone},
336+
{"sanitize-config", module_sanitize_config},
271337
};
272338

273339
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)

git-submodule.sh

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,16 @@ isnumber()
192192
n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
193193
}
194194

195+
# Sanitize the local git environment for use within a submodule. We
196+
# can't simply use clear_local_git_env since we want to preserve some
197+
# of the settings from GIT_CONFIG_PARAMETERS.
198+
sanitize_submodule_env()
199+
{
200+
sanitized_config=$(git submodule--helper sanitize-config)
201+
clear_local_git_env
202+
GIT_CONFIG_PARAMETERS=$sanitized_config
203+
}
204+
195205
#
196206
# Add a new submodule to the working tree, .gitmodules and the index
197207
#
@@ -349,7 +359,7 @@ Use -f if you really want to add it." >&2
349359
fi
350360
git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${depth:+"$depth"} || exit
351361
(
352-
clear_local_git_env
362+
sanitize_submodule_env
353363
cd "$sm_path" &&
354364
# ash fails to wordsplit ${branch:+-b "$branch"...}
355365
case "$branch" in
@@ -418,7 +428,7 @@ cmd_foreach()
418428
name=$(git submodule--helper name "$sm_path")
419429
(
420430
prefix="$prefix$sm_path/"
421-
clear_local_git_env
431+
sanitize_submodule_env
422432
cd "$sm_path" &&
423433
sm_path=$(relative_path "$sm_path") &&
424434
# we make $path available to scripts ...
@@ -713,7 +723,7 @@ Maybe you want to use 'update --init'?")"
713723
cloned_modules="$cloned_modules;$name"
714724
subsha1=
715725
else
716-
subsha1=$(clear_local_git_env; cd "$sm_path" &&
726+
subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
717727
git rev-parse --verify HEAD) ||
718728
die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
719729
fi
@@ -723,11 +733,11 @@ Maybe you want to use 'update --init'?")"
723733
if test -z "$nofetch"
724734
then
725735
# Fetch remote before determining tracking $sha1
726-
(clear_local_git_env; cd "$sm_path" && git-fetch) ||
736+
(sanitize_submodule_env; cd "$sm_path" && git-fetch) ||
727737
die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
728738
fi
729-
remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
730-
sha1=$(clear_local_git_env; cd "$sm_path" &&
739+
remote_name=$(sanitize_submodule_env; cd "$sm_path" && get_default_remote)
740+
sha1=$(sanitize_submodule_env; cd "$sm_path" &&
731741
git rev-parse --verify "${remote_name}/${branch}") ||
732742
die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
733743
fi
@@ -745,7 +755,7 @@ Maybe you want to use 'update --init'?")"
745755
then
746756
# Run fetch only if $sha1 isn't present or it
747757
# is not reachable from a ref.
748-
(clear_local_git_env; cd "$sm_path" &&
758+
(sanitize_submodule_env; cd "$sm_path" &&
749759
( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) &&
750760
test -z "$rev") || git-fetch)) ||
751761
die "$(eval_gettext "Unable to fetch in submodule path '\$displaypath'")"
@@ -787,7 +797,7 @@ Maybe you want to use 'update --init'?")"
787797
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
788798
esac
789799

790-
if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
800+
if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")
791801
then
792802
say "$say_msg"
793803
elif test -n "$must_die_on_failure"
@@ -803,7 +813,7 @@ Maybe you want to use 'update --init'?")"
803813
then
804814
(
805815
prefix="$prefix$sm_path/"
806-
clear_local_git_env
816+
sanitize_submodule_env
807817
cd "$sm_path" &&
808818
eval cmd_update
809819
)
@@ -841,7 +851,7 @@ Maybe you want to use 'update --init'?")"
841851

842852
set_name_rev () {
843853
revname=$( (
844-
clear_local_git_env
854+
sanitize_submodule_env
845855
cd "$1" && {
846856
git describe "$2" 2>/dev/null ||
847857
git describe --tags "$2" 2>/dev/null ||
@@ -1125,7 +1135,7 @@ cmd_status()
11251135
else
11261136
if test -z "$cached"
11271137
then
1128-
sha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD)
1138+
sha1=$(sanitize_submodule_env; cd "$sm_path" && git rev-parse --verify HEAD)
11291139
fi
11301140
set_name_rev "$sm_path" "$sha1"
11311141
say "+$sha1 $displaypath$revname"
@@ -1135,7 +1145,7 @@ cmd_status()
11351145
then
11361146
(
11371147
prefix="$displaypath/"
1138-
clear_local_git_env
1148+
sanitize_submodule_env
11391149
cd "$sm_path" &&
11401150
eval cmd_status
11411151
) ||
@@ -1209,7 +1219,7 @@ cmd_sync()
12091219
if test -e "$sm_path"/.git
12101220
then
12111221
(
1212-
clear_local_git_env
1222+
sanitize_submodule_env
12131223
cd "$sm_path"
12141224
remote=$(get_default_remote)
12151225
git config remote."$remote".url "$sub_origin_url"

t/t5550-http-fetch-dumb.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,23 @@ test_expect_success 'configured username does not override URL' '
9191
expect_askpass pass user@host
9292
'
9393

94+
test_expect_success 'cmdline credential config passes into submodules' '
95+
git init super &&
96+
set_askpass user@host pass@host &&
97+
(
98+
cd super &&
99+
git submodule add "$HTTPD_URL/auth/dumb/repo.git" sub &&
100+
git commit -m "add submodule"
101+
) &&
102+
set_askpass wrong pass@host &&
103+
test_must_fail git clone --recursive super super-clone &&
104+
rm -rf super-clone &&
105+
set_askpass wrong pass@host &&
106+
git -c "credential.$HTTP_URL.username=user@host" \
107+
clone --recursive super super-clone &&
108+
expect_askpass pass user@host
109+
'
110+
94111
test_expect_success 'fetch changes via http' '
95112
echo content >>file &&
96113
git commit -a -m two &&

t/t7412-submodule--helper.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2016 Jacob Keller
4+
#
5+
6+
test_description='Basic plumbing support of submodule--helper
7+
8+
This test verifies the submodule--helper plumbing command used to implement
9+
git-submodule.
10+
'
11+
12+
. ./test-lib.sh
13+
14+
test_expect_success 'sanitize-config clears configuration' '
15+
git -c user.name="Some User" submodule--helper sanitize-config >actual &&
16+
test_must_be_empty actual
17+
'
18+
19+
sq="'"
20+
test_expect_success 'sanitize-config keeps credential.helper' '
21+
git -c credential.helper=helper submodule--helper sanitize-config >actual &&
22+
echo "${sq}credential.helper=helper${sq}" >expect &&
23+
test_cmp expect actual
24+
'
25+
26+
test_done

0 commit comments

Comments
 (0)