Skip to content

Commit af4d620

Browse files
committed
Merge branch 'scalar-and-non-interactive-authentication-in-maintenance'
This topic branch first merges the topic branch that teaches background maintenance to avoid trying to authenticate interactively, and then teaches `scalar reconfigure` to enforce that. Signed-off-by: Johannes Schindelin <[email protected]>
2 parents f8819fa + 3c6cd1f commit af4d620

File tree

7 files changed

+114
-13
lines changed

7 files changed

+114
-13
lines changed

Documentation/config/credential.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ credential.helper::
99
Note that multiple helpers may be defined. See linkgit:gitcredentials[7]
1010
for details and examples.
1111

12+
credential.interactive::
13+
By default, Git and any configured credential helpers will ask for
14+
user input when new credentials are required. Many of these helpers
15+
will succeed based on stored credentials if those credentials are
16+
still valid. To avoid the possibility of user interactivity from
17+
Git, set `credential.interactive=false`. Some credential helpers
18+
respect this option as well.
19+
1220
credential.useHttpPath::
1321
When acquiring credentials, consider the "path" component of an http
1422
or https URL to be important. Defaults to false. See

builtin/gc.c

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,42 @@ static const char *get_frequency(enum schedule_priority schedule)
16861686
}
16871687
}
16881688

1689+
static const char *extraconfig[] = {
1690+
"credential.interactive=false",
1691+
"core.askPass=true", /* 'true' returns success, but no output. */
1692+
NULL
1693+
};
1694+
1695+
static const char *get_extra_config_parameters(void) {
1696+
static const char *result = NULL;
1697+
struct strbuf builder = STRBUF_INIT;
1698+
1699+
if (result)
1700+
return result;
1701+
1702+
for (const char **s = extraconfig; s && *s; s++)
1703+
strbuf_addf(&builder, "-c %s ", *s);
1704+
1705+
result = strbuf_detach(&builder, NULL);
1706+
return result;
1707+
}
1708+
1709+
static const char *get_extra_launchctl_strings(void) {
1710+
static const char *result = NULL;
1711+
struct strbuf builder = STRBUF_INIT;
1712+
1713+
if (result)
1714+
return result;
1715+
1716+
for (const char **s = extraconfig; s && *s; s++) {
1717+
strbuf_addstr(&builder, "<string>-c</string>\n");
1718+
strbuf_addf(&builder, "<string>%s</string>\n", *s);
1719+
}
1720+
1721+
result = strbuf_detach(&builder, NULL);
1722+
return result;
1723+
}
1724+
16891725
/*
16901726
* get_schedule_cmd` reads the GIT_TEST_MAINT_SCHEDULER environment variable
16911727
* to mock the schedulers that `git maintenance start` rely on.
@@ -1892,6 +1928,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
18921928
"<array>\n"
18931929
"<string>%s/git</string>\n"
18941930
"<string>--exec-path=%s</string>\n"
1931+
"%s" /* For extra config parameters. */
18951932
"<string>for-each-repo</string>\n"
18961933
"<string>--keep-going</string>\n"
18971934
"<string>--config=maintenance.repo</string>\n"
@@ -1901,7 +1938,8 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
19011938
"</array>\n"
19021939
"<key>StartCalendarInterval</key>\n"
19031940
"<array>\n";
1904-
strbuf_addf(&plist, preamble, name, exec_path, exec_path, frequency);
1941+
strbuf_addf(&plist, preamble, name, exec_path, exec_path,
1942+
get_extra_launchctl_strings(), frequency);
19051943

19061944
switch (schedule) {
19071945
case SCHEDULE_HOURLY:
@@ -2136,11 +2174,12 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
21362174
"<Actions Context=\"Author\">\n"
21372175
"<Exec>\n"
21382176
"<Command>\"%s\\headless-git.exe\"</Command>\n"
2139-
"<Arguments>--exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
2177+
"<Arguments>--exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
21402178
"</Exec>\n"
21412179
"</Actions>\n"
21422180
"</Task>\n";
2143-
fprintf(tfile->fp, xml, exec_path, exec_path, frequency);
2181+
fprintf(tfile->fp, xml, exec_path, exec_path,
2182+
get_extra_config_parameters(), frequency);
21442183
strvec_split(&child.args, cmd);
21452184
strvec_pushl(&child.args, "/create", "/tn", name, "/f", "/xml",
21462185
get_tempfile_path(tfile), NULL);
@@ -2281,8 +2320,8 @@ static int crontab_update_schedule(int run_maintenance, int fd)
22812320
"# replaced in the future by a Git command.\n\n");
22822321

22832322
strbuf_addf(&line_format,
2284-
"%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
2285-
exec_path, exec_path);
2323+
"%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
2324+
exec_path, exec_path, get_extra_config_parameters());
22862325
fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
22872326
fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
22882327
fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
@@ -2482,7 +2521,7 @@ static int systemd_timer_write_service_template(const char *exec_path)
24822521
"\n"
24832522
"[Service]\n"
24842523
"Type=oneshot\n"
2485-
"ExecStart=\"%s/git\" --exec-path=\"%s\" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
2524+
"ExecStart=\"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
24862525
"LockPersonality=yes\n"
24872526
"MemoryDenyWriteExecute=yes\n"
24882527
"NoNewPrivileges=yes\n"
@@ -2492,7 +2531,7 @@ static int systemd_timer_write_service_template(const char *exec_path)
24922531
"RestrictSUIDSGID=yes\n"
24932532
"SystemCallArchitectures=native\n"
24942533
"SystemCallFilter=@system-service\n";
2495-
if (fprintf(file, unit, exec_path, exec_path) < 0) {
2534+
if (fprintf(file, unit, exec_path, exec_path, get_extra_config_parameters()) < 0) {
24962535
error(_("failed to write to '%s'"), filename);
24972536
fclose(file);
24982537
goto error;

credential.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#define USE_THE_REPOSITORY_VARIABLE
12
#include "git-compat-util.h"
23
#include "abspath.h"
34
#include "config.h"
@@ -11,6 +12,8 @@
1112
#include "strbuf.h"
1213
#include "urlmatch.h"
1314
#include "git-compat-util.h"
15+
#include "trace2.h"
16+
#include "repository.h"
1417

1518
void credential_init(struct credential *c)
1619
{
@@ -249,14 +252,36 @@ static char *credential_ask_one(const char *what, struct credential *c,
249252
return xstrdup(r);
250253
}
251254

252-
static void credential_getpass(struct credential *c)
255+
static int credential_getpass(struct credential *c)
253256
{
257+
int interactive;
258+
char *value;
259+
if (!git_config_get_maybe_bool("credential.interactive", &interactive) &&
260+
!interactive) {
261+
trace2_data_intmax("credential", the_repository,
262+
"interactive/skipped", 1);
263+
return -1;
264+
}
265+
if (!git_config_get_string("credential.interactive", &value)) {
266+
int same = !strcmp(value, "never");
267+
free(value);
268+
if (same) {
269+
trace2_data_intmax("credential", the_repository,
270+
"interactive/skipped", 1);
271+
return -1;
272+
}
273+
}
274+
275+
trace2_region_enter("credential", "interactive", the_repository);
254276
if (!c->username)
255277
c->username = credential_ask_one("Username", c,
256278
PROMPT_ASKPASS|PROMPT_ECHO);
257279
if (!c->password)
258280
c->password = credential_ask_one("Password", c,
259281
PROMPT_ASKPASS);
282+
trace2_region_leave("credential", "interactive", the_repository);
283+
284+
return 0;
260285
}
261286

262287
int credential_has_capability(const struct credential_capability *capa,
@@ -501,8 +526,8 @@ void credential_fill(struct credential *c, int all_capabilities)
501526
c->helpers.items[i].string);
502527
}
503528

504-
credential_getpass(c);
505-
if (!c->username && !c->password && !c->credential)
529+
if (credential_getpass(c) ||
530+
(!c->username && !c->password && !c->credential))
506531
die("unable to get password from user");
507532
}
508533

scalar.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,8 @@ static int cmd_reconfigure(int argc, const char **argv)
11091109
old_repo = the_repository;
11101110
the_repository = &r;
11111111

1112-
if (set_recommended_config(1) >= 0)
1112+
if (set_recommended_config(1) >= 0 &&
1113+
toggle_maintenance(1) >= 0)
11131114
succeeded = 1;
11141115

11151116
the_repository = old_repo;

t/t5551-http-fetch-smart.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,28 @@ test_expect_success 'clone from password-protected repository' '
186186
test_cmp expect actual
187187
'
188188

189+
test_expect_success 'credential.interactive=false skips askpass' '
190+
set_askpass bogus nonsense &&
191+
(
192+
GIT_TRACE2_EVENT="$(pwd)/interactive-true" &&
193+
export GIT_TRACE2_EVENT &&
194+
test_must_fail git clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-true-dir &&
195+
test_region credential interactive interactive-true &&
196+
197+
GIT_TRACE2_EVENT="$(pwd)/interactive-false" &&
198+
export GIT_TRACE2_EVENT &&
199+
test_must_fail git -c credential.interactive=false \
200+
clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-false-dir &&
201+
test_region ! credential interactive interactive-false &&
202+
203+
GIT_TRACE2_EVENT="$(pwd)/interactive-never" &&
204+
export GIT_TRACE2_EVENT &&
205+
test_must_fail git -c credential.interactive=never \
206+
clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-never-dir &&
207+
test_region ! credential interactive interactive-never
208+
)
209+
'
210+
189211
test_expect_success 'clone from auth-only-for-push repository' '
190212
echo two >expect &&
191213
set_askpass wrong &&

t/t7900-maintenance.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,9 @@ test_expect_success 'start and stop Linux/systemd maintenance' '
800800
test_systemd_analyze_verify "systemd/user/[email protected]" &&
801801
test_systemd_analyze_verify "systemd/user/[email protected]" &&
802802
803+
grep "core.askPass=true" "systemd/user/[email protected]" &&
804+
grep "credential.interactive=false" "systemd/user/[email protected]" &&
805+
803806
printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
804807
test_cmp expect args &&
805808

t/t9210-scalar.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,11 @@ test_expect_success 'scalar reconfigure' '
183183
scalar reconfigure one &&
184184
test true = "$(git -C one/src config core.preloadIndex)" &&
185185
git -C one/src config core.preloadIndex false &&
186-
scalar reconfigure -a &&
187-
test true = "$(git -C one/src config core.preloadIndex)"
186+
rm one/src/cron.txt &&
187+
GIT_TRACE2_EVENT="$(pwd)/reconfigure" scalar reconfigure -a &&
188+
test_path_is_file one/src/cron.txt &&
189+
test true = "$(git -C one/src config core.preloadIndex)" &&
190+
test_subcommand git maintenance start <reconfigure
188191
'
189192

190193
test_expect_success 'scalar reconfigure --all with includeIf.onbranch' '

0 commit comments

Comments
 (0)