Skip to content

Commit 34348f5

Browse files
jacob-kellerdscho
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 3a70ab5 commit 34348f5

File tree

4 files changed

+132
-13
lines changed

4 files changed

+132
-13
lines changed

builtin/submodule--helper.c

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

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

141190
cp.git_cmd = 1;
142-
cp.env = local_repo_env;
191+
prepare_submodule_repo_env(&cp.env_array);
143192
cp.no_stdin = 1;
144193

145194
return run_command(&cp);
@@ -253,6 +302,22 @@ static int module_clone(int argc, const char **argv, const char *prefix)
253302
return 0;
254303
}
255304

305+
static int module_sanitize_config(int argc, const char **argv, const char *prefix)
306+
{
307+
struct strbuf sanitized_config = STRBUF_INIT;
308+
309+
if (argc > 1)
310+
usage(_("git submodule--helper sanitize-config"));
311+
312+
git_config_from_parameters(sanitize_submodule_config, &sanitized_config);
313+
if (sanitized_config.len)
314+
printf("%s\n", sanitized_config.buf);
315+
316+
strbuf_release(&sanitized_config);
317+
318+
return 0;
319+
}
320+
256321
struct cmd_struct {
257322
const char *cmd;
258323
int (*fn)(int, const char **, const char *);
@@ -262,6 +327,7 @@ static struct cmd_struct commands[] = {
262327
{"list", module_list},
263328
{"name", module_name},
264329
{"clone", module_clone},
330+
{"sanitize-config", module_sanitize_config},
265331
};
266332

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

git-submodule.sh

Lines changed: 22 additions & 12 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 ...
@@ -731,7 +741,7 @@ Maybe you want to use 'update --init'?")"
731741
cloned_modules="$cloned_modules;$name"
732742
subsha1=
733743
else
734-
subsha1=$(clear_local_git_env; cd "$sm_path" &&
744+
subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
735745
git rev-parse --verify HEAD) ||
736746
die "$(eval_gettext "Unable to find current revision in submodule path '\$displaypath'")"
737747
fi
@@ -741,11 +751,11 @@ Maybe you want to use 'update --init'?")"
741751
if test -z "$nofetch"
742752
then
743753
# Fetch remote before determining tracking $sha1
744-
(clear_local_git_env; cd "$sm_path" && git-fetch) ||
754+
(sanitize_submodule_env; cd "$sm_path" && git-fetch) ||
745755
die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
746756
fi
747-
remote_name=$(clear_local_git_env; cd "$sm_path" && get_default_remote)
748-
sha1=$(clear_local_git_env; cd "$sm_path" &&
757+
remote_name=$(sanitize_submodule_env; cd "$sm_path" && get_default_remote)
758+
sha1=$(sanitize_submodule_env; cd "$sm_path" &&
749759
git rev-parse --verify "${remote_name}/${branch}") ||
750760
die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
751761
fi
@@ -810,7 +820,7 @@ Maybe you want to use 'update --init'?")"
810820
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
811821
esac
812822

813-
if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
823+
if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")
814824
then
815825
say "$say_msg"
816826
elif test -n "$must_die_on_failure"
@@ -826,7 +836,7 @@ Maybe you want to use 'update --init'?")"
826836
then
827837
(
828838
prefix="$prefix$sm_path/"
829-
clear_local_git_env
839+
sanitize_submodule_env
830840
cd "$sm_path" &&
831841
eval cmd_update
832842
)
@@ -864,7 +874,7 @@ Maybe you want to use 'update --init'?")"
864874

865875
set_name_rev () {
866876
revname=$( (
867-
clear_local_git_env
877+
sanitize_submodule_env
868878
cd "$1" && {
869879
git describe "$2" 2>/dev/null ||
870880
git describe --tags "$2" 2>/dev/null ||
@@ -1148,7 +1158,7 @@ cmd_status()
11481158
else
11491159
if test -z "$cached"
11501160
then
1151-
sha1=$(clear_local_git_env; cd "$sm_path" && git rev-parse --verify HEAD)
1161+
sha1=$(sanitize_submodule_env; cd "$sm_path" && git rev-parse --verify HEAD)
11521162
fi
11531163
set_name_rev "$sm_path" "$sha1"
11541164
say "+$sha1 $displaypath$revname"
@@ -1158,7 +1168,7 @@ cmd_status()
11581168
then
11591169
(
11601170
prefix="$displaypath/"
1161-
clear_local_git_env
1171+
sanitize_submodule_env
11621172
cd "$sm_path" &&
11631173
eval cmd_status
11641174
) ||
@@ -1232,7 +1242,7 @@ cmd_sync()
12321242
if test -e "$sm_path"/.git
12331243
then
12341244
(
1235-
clear_local_git_env
1245+
sanitize_submodule_env
12361246
cd "$sm_path"
12371247
remote=$(get_default_remote)
12381248
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)