Message ID | 94b40907e66b2f6e0874ab49f8b73fdd58eb06d5.1654635432.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | config: introduce discovery.bare and protected config | expand |
"Glen Choo via GitGitGadget" <gitgitgadget@gmail.com> writes: > diff --git a/upload-pack.c b/upload-pack.c > index 3a851b36066..09f48317b02 100644 > --- a/upload-pack.c > +++ b/upload-pack.c > @@ -1321,18 +1321,27 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) > data->advertise_sid = git_config_bool(var, value); > } > > - if (current_config_scope() != CONFIG_SCOPE_LOCAL && > - current_config_scope() != CONFIG_SCOPE_WORKTREE) { > - if (!strcmp("uploadpack.packobjectshook", var)) > - return git_config_string(&data->pack_objects_hook, var, value); > - } > - The lossage of this block is because this general git_config() callback routine that is used to read from any scope is no longer used to pick up the sensitive variable. Instead, we need to get it with a different API, namely, git_protected_config(). It is probably is good that in the new code we are not encouraging folks to write random comparisons on current_config_scope(), and instead uniformly use a git_protected_config(). That may promote consistency. An obvious alternative to achieve the same consistency would be to introduce a helper, and rewrite (instead of removing) the above part like so: if (in_protected_scope()) { ... parse sensitive variable ... } We would not need any other change to this file in this patch if we go that route, I suspect. > if (parse_object_filter_config(var, value, data) < 0) > return -1; > > return parse_hide_refs_config(var, value, "uploadpack"); > } > > +static int upload_pack_protected_config(const char *var, const char *value, void *cb_data) > +{ > + struct upload_pack_data *data = cb_data; > + > + if (!strcmp("uploadpack.packobjectshook", var)) > + return git_config_string(&data->pack_objects_hook, var, value); > + return 0; > +} > + > +static void get_upload_pack_config(struct upload_pack_data *data) > +{ > + git_config(upload_pack_config, data); > + git_protected_config(upload_pack_protected_config, data); > +} Where we used to just do git_config(upload_pack_config), we now need to do a separate git_protected_config(). It feels a bit wasteful to iterate over the same configset twice, but it is not like we are doing the IO and text file parsing multiple times. This looks quite straight-forward.
Junio C Hamano <gitster@pobox.com> writes: > "Glen Choo via GitGitGadget" <gitgitgadget@gmail.com> writes: > >> diff --git a/upload-pack.c b/upload-pack.c >> index 3a851b36066..09f48317b02 100644 >> --- a/upload-pack.c >> +++ b/upload-pack.c >> @@ -1321,18 +1321,27 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) >> data->advertise_sid = git_config_bool(var, value); >> } >> >> - if (current_config_scope() != CONFIG_SCOPE_LOCAL && >> - current_config_scope() != CONFIG_SCOPE_WORKTREE) { >> - if (!strcmp("uploadpack.packobjectshook", var)) >> - return git_config_string(&data->pack_objects_hook, var, value); >> - } >> - > > The lossage of this block is because this general git_config() > callback routine that is used to read from any scope is no longer > used to pick up the sensitive variable. Instead, we need to get it > with a different API, namely, git_protected_config(). > > It is probably is good that in the new code we are not encouraging > folks to write random comparisons on current_config_scope(), and > instead uniformly use a git_protected_config(). That may promote > consistency. > > An obvious alternative to achieve the same consistency would be to > introduce a helper, and rewrite (instead of removing) the above part > like so: > > if (in_protected_scope()) { > ... parse sensitive variable ... > } > > We would not need any other change to this file in this patch if we > go that route, I suspect. Yes, and as noted in the commit message, this approach seems to work for `safe.directory` and `discovery.bare` too. >> if (parse_object_filter_config(var, value, data) < 0) >> return -1; >> >> return parse_hide_refs_config(var, value, "uploadpack"); >> } >> >> +static int upload_pack_protected_config(const char *var, const char *value, void *cb_data) >> +{ >> + struct upload_pack_data *data = cb_data; >> + >> + if (!strcmp("uploadpack.packobjectshook", var)) >> + return git_config_string(&data->pack_objects_hook, var, value); >> + return 0; >> +} >> + >> +static void get_upload_pack_config(struct upload_pack_data *data) >> +{ >> + git_config(upload_pack_config, data); >> + git_protected_config(upload_pack_protected_config, data); >> +} > > Where we used to just do git_config(upload_pack_config), we now need > to do a separate git_protected_config(). It feels a bit wasteful to > iterate over the same configset twice, but it is not like we are > doing the IO and text file parsing multiple times. This looks quite > straight-forward. Yeah it's not optimal, but at the very least, I think it's easy enough to understand that we could replace it with something more economical in the future.
diff --git a/config.c b/config.c index fa471dbdb89..56b7ed5ffe8 100644 --- a/config.c +++ b/config.c @@ -81,6 +81,18 @@ static enum config_scope current_parsing_scope; static int pack_compression_seen; static int zlib_compression_seen; +/* + * Config that comes from trusted sources, namely: + * - system config files (e.g. /etc/gitconfig) + * - global config files (e.g. $HOME/.gitconfig, + * $XDG_CONFIG_HOME/git) + * - the command line. + * + * This is declared here for code cleanliness, but unlike the other + * static variables, this does not hold config parser state. + */ +static struct config_set protected_config; + static int config_file_fgetc(struct config_source *conf) { return getc_unlocked(conf->u.file); @@ -2373,6 +2385,11 @@ int git_configset_add_file(struct config_set *cs, const char *filename) return git_config_from_file(config_set_callback, filename, cs); } +int git_configset_add_parameters(struct config_set *cs) +{ + return git_config_from_parameters(config_set_callback, cs); +} + int git_configset_get_value(struct config_set *cs, const char *key, const char **value) { const struct string_list *values = NULL; @@ -2614,6 +2631,40 @@ int repo_config_get_pathname(struct repository *repo, return ret; } +/* Read values into protected_config. */ +static void read_protected_config(void) +{ + char *xdg_config = NULL, *user_config = NULL, *system_config = NULL; + + git_configset_init(&protected_config); + + system_config = git_system_config(); + git_global_config(&user_config, &xdg_config); + + git_configset_add_file(&protected_config, system_config); + git_configset_add_file(&protected_config, xdg_config); + git_configset_add_file(&protected_config, user_config); + git_configset_add_parameters(&protected_config); + + free(system_config); + free(xdg_config); + free(user_config); +} + +/* Ensure that protected_config has been initialized. */ +static void git_protected_config_check_init(void) +{ + if (protected_config.hash_initialized) + return; + read_protected_config(); +} + +void git_protected_config(config_fn_t fn, void *data) +{ + git_protected_config_check_init(); + configset_iter(&protected_config, fn, data); +} + /* Functions used historically to read configuration from 'the_repository' */ void git_config(config_fn_t fn, void *data) { diff --git a/config.h b/config.h index 7654f61c634..e3ff1fcf683 100644 --- a/config.h +++ b/config.h @@ -446,6 +446,15 @@ void git_configset_init(struct config_set *cs); */ int git_configset_add_file(struct config_set *cs, const char *filename); +/** + * Parses command line options and environment variables, and adds the + * variable-value pairs to the `config_set`. Returns 0 on success, or -1 + * if there is an error in parsing. The caller decides whether to free + * the incomplete configset or continue using it when the function + * returns -1. + */ +int git_configset_add_parameters(struct config_set *cs); + /** * Finds and returns the value list, sorted in order of increasing priority * for the configuration variable `key` and config set `cs`. When the @@ -505,6 +514,14 @@ int repo_config_get_maybe_bool(struct repository *repo, int repo_config_get_pathname(struct repository *repo, const char *key, const char **dest); +/* + * Functions for reading protected config. By definition, protected + * config ignores repository config, so it is unnecessary to read + * protected config from any `struct repository` other than + * the_repository. + */ +void git_protected_config(config_fn_t fn, void *data); + /** * Querying For Specific Variables * ------------------------------- diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh index dd5f44d986f..54f54f8d2eb 100755 --- a/t/t5544-pack-objects-hook.sh +++ b/t/t5544-pack-objects-hook.sh @@ -56,7 +56,12 @@ test_expect_success 'hook does not run from repo config' ' ! grep "hook running" stderr && test_path_is_missing .git/hook.args && test_path_is_missing .git/hook.stdin && - test_path_is_missing .git/hook.stdout + test_path_is_missing .git/hook.stdout && + + # check that global config is used instead + test_config_global uploadpack.packObjectsHook ./hook && + git clone --no-local . dst2.git 2>stderr && + grep "hook running" stderr ' test_expect_success 'hook works with partial clone' ' diff --git a/upload-pack.c b/upload-pack.c index 3a851b36066..09f48317b02 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -1321,18 +1321,27 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) data->advertise_sid = git_config_bool(var, value); } - if (current_config_scope() != CONFIG_SCOPE_LOCAL && - current_config_scope() != CONFIG_SCOPE_WORKTREE) { - if (!strcmp("uploadpack.packobjectshook", var)) - return git_config_string(&data->pack_objects_hook, var, value); - } - if (parse_object_filter_config(var, value, data) < 0) return -1; return parse_hide_refs_config(var, value, "uploadpack"); } +static int upload_pack_protected_config(const char *var, const char *value, void *cb_data) +{ + struct upload_pack_data *data = cb_data; + + if (!strcmp("uploadpack.packobjectshook", var)) + return git_config_string(&data->pack_objects_hook, var, value); + return 0; +} + +static void get_upload_pack_config(struct upload_pack_data *data) +{ + git_config(upload_pack_config, data); + git_protected_config(upload_pack_protected_config, data); +} + void upload_pack(const int advertise_refs, const int stateless_rpc, const int timeout) { @@ -1340,8 +1349,7 @@ void upload_pack(const int advertise_refs, const int stateless_rpc, struct upload_pack_data data; upload_pack_data_init(&data); - - git_config(upload_pack_config, &data); + get_upload_pack_config(&data); data.stateless_rpc = stateless_rpc; data.timeout = timeout; @@ -1695,8 +1703,7 @@ int upload_pack_v2(struct repository *r, struct packet_reader *request) upload_pack_data_init(&data); data.use_sideband = LARGE_PACKET_MAX; - - git_config(upload_pack_config, &data); + get_upload_pack_config(&data); while (state != FETCH_DONE) { switch (state) {