git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Christian Couder <christian.couder@gmail.com>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>,
	Patrick Steinhardt <ps@pks.im>, Taylor Blau <me@ttaylorr.com>,
	Karthik Nayak <karthik.188@gmail.com>,
	Christian Couder <christian.couder@gmail.com>,
	Christian Couder <chriscool@tuxfamily.org>
Subject: [PATCH 4/4] promisor-remote: allow a client to check extra fields
Date: Mon, 14 Apr 2025 18:03:43 +0200	[thread overview]
Message-ID: <20250414160343.2216312-5-christian.couder@gmail.com> (raw)
In-Reply-To: <20250414160343.2216312-1-christian.couder@gmail.com>

A previous commit allowed a server to pass extra fields through the
"promisor-remote" protocol capability after the "name" and "url"
fields.

Let's make it possible for a client to check if these extra fields
match what it expects before accepting a promisor remote.

We allow this by introducing a new "promisor.checkExtraFields"
configuration variable. It should contain a comma or space
separated list of fields that will be checked.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 Documentation/config/promisor.adoc    |  17 +++++
 promisor-remote.c                     | 102 +++++++++++++++++++++++---
 t/t5710-promisor-remote-capability.sh |  35 +++++++++
 3 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/Documentation/config/promisor.adoc b/Documentation/config/promisor.adoc
index bc08999733..75207de2ac 100644
--- a/Documentation/config/promisor.adoc
+++ b/Documentation/config/promisor.adoc
@@ -43,3 +43,20 @@ promisor.acceptFromServer::
 	lazily fetchable from this promisor remote from its responses
 	to "fetch" and "clone" requests from the client. Name and URL
 	comparisons are case sensitive. See linkgit:gitprotocol-v2[5].
+
+promisor.checkExtraFields::
+	A comma or space separated list of additional remote related
+	fields that a client will check before accepting a promisor
+	remote. When a field named "bar" is part of this list and a
+	corresponding "remote.foo.bar" config variable is set for
+	locally for remote "foo", then the value of the
+	"remote.foo.bar" config variable will be checked against the
+	value of the "bar" field passed by the server through the
+	"promisor-remote" capability for the remote "foo". The remote
+	"foo" will be rejected if the values don't match. The fields
+	should be passed by the server through the "promisor-remote"
+	capability by using the `promisor.sendExtraFields` config
+	variable, see above. The extra fields will be checked only if
+	the `promisor.acceptFromServer` config variable, see above, is
+	not set to "None". If is set to "None", this config variable
+	will have no effect. See linkgit:gitprotocol-v2[5].
diff --git a/promisor-remote.c b/promisor-remote.c
index 424d88d4a1..3645093f2f 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -358,6 +358,19 @@ static struct string_list *extra_fields_sent(void)
 	return &fields_list;
 }
 
+static struct string_list *extra_fields_checked(void)
+{
+	static struct string_list fields_list = STRING_LIST_INIT_NODUP;
+	static int initialized = 0;
+
+	if (!initialized) {
+		fields_from_config(&fields_list, "promisor.checkExtraFields");
+		initialized = 1;
+	}
+
+	return &fields_list;
+}
+
 static void append_extra_fields(struct string_list *fields,
 				struct string_list *extra_fields,
 				const char *name)
@@ -497,15 +510,65 @@ enum accept_promisor {
 	ACCEPT_ALL
 };
 
+static int check_extra_field_one(struct string_list_item *item_value,
+				 struct promisor_info *p)
+{
+	struct string_list_item *item;
+
+	item = unsorted_string_list_lookup(&p->fields, item_value->string);
+	if (!item)
+		return 0;
+
+	return !strcmp(item->util, item_value->util);
+}
+
+
+static int check_extra_field(struct string_list_item *item_value,
+			     struct promisor_info *p, int in_list)
+{
+	if (!in_list)
+		return check_extra_field_one(item_value, p);
+
+	for (; p; p = p->next)
+		if (check_extra_field_one(item_value, p))
+			return 1;
+
+	return 0;
+}
+
+static int check_all_extra_fields(struct string_list* extra_values,
+				  struct promisor_info *p,
+				  int in_list)
+{
+	struct string_list* fields_checked = extra_fields_checked();
+	struct string_list_item *item_checked;
+
+	string_list_sort(extra_values);
+
+	for_each_string_list_item(item_checked, fields_checked) {
+		struct string_list_item *item_value;
+
+		item_value = string_list_lookup(extra_values, item_checked->string);
+		if (!item_value)
+			return 0;
+		if (!check_extra_field(item_value, p, in_list))
+			return 0;
+	}
+
+	return 1;
+}
+
 static int should_accept_remote(enum accept_promisor accept,
-				const char *remote_name, const char *remote_url,
+				const char *remote_name,
+				const char *remote_url,
+				struct string_list* extras,
 				struct promisor_info *info_list)
 {
 	struct promisor_info *p;
 	const char *local_url;
 
 	if (accept == ACCEPT_ALL)
-		return 1;
+		return check_all_extra_fields(extras, info_list, 1);
 
 	p = remote_nick_find(info_list, remote_name);
 
@@ -514,7 +577,7 @@ static int should_accept_remote(enum accept_promisor accept,
 		return 0;
 
 	if (accept == ACCEPT_KNOWN_NAME)
-		return 1;
+		return check_all_extra_fields(extras, p, 0);
 
 	if (accept != ACCEPT_KNOWN_URL)
 		BUG("Unhandled 'enum accept_promisor' value '%d'", accept);
@@ -530,7 +593,7 @@ static int should_accept_remote(enum accept_promisor accept,
 	local_url = p->fields.items[1].util;
 
 	if (!strcmp(local_url, remote_url))
-		return 1;
+		return check_all_extra_fields(extras, p, 0);
 
 	warning(_("known remote named '%s' but with URL '%s' instead of '%s'"),
 		remote_name, local_url, remote_url);
@@ -564,9 +627,6 @@ static void filter_promisor_remote(struct repository *repo,
 	if (accept == ACCEPT_NONE)
 		return;
 
-	if (accept != ACCEPT_ALL)
-		info_list = promisor_info_list(repo, NULL);
-
 	/* Parse remote info received */
 
 	remotes = strbuf_split_str(info, ';', 0);
@@ -577,14 +637,27 @@ static void filter_promisor_remote(struct repository *repo,
 		const char *remote_url = NULL;
 		char *decoded_name = NULL;
 		char *decoded_url = NULL;
+		struct string_list extras = STRING_LIST_INIT_NODUP;
 
 		strbuf_strip_suffix(remotes[i], ";");
 		elems = strbuf_split(remotes[i], ',');
 
 		for (size_t j = 0; elems[j]; j++) {
+			char *p;
+
 			strbuf_strip_suffix(elems[j], ",");
-			if (!skip_prefix(elems[j]->buf, "name=", &remote_name))
-				skip_prefix(elems[j]->buf, "url=", &remote_url);
+			if (skip_prefix(elems[j]->buf, "name=", &remote_name) ||
+			    skip_prefix(elems[j]->buf, "url=", &remote_url))
+				continue;
+
+			p = strchr(elems[j]->buf, '=');
+			if (p) {
+				*p = '\0';
+				string_list_append(&extras, elems[j]->buf)->util = p + 1;
+			} else {
+				warning(_("invalid element '%s' from remote info"),
+					elems[j]->buf);
+			}
 		}
 
 		if (remote_name)
@@ -592,9 +665,16 @@ static void filter_promisor_remote(struct repository *repo,
 		if (remote_url)
 			decoded_url = url_percent_decode(remote_url);
 
-		if (decoded_name && should_accept_remote(accept, decoded_name, decoded_url, info_list))
-			strvec_push(accepted, decoded_name);
+		if (decoded_name) {
+			if (!info_list)
+				info_list = promisor_info_list(repo, extra_fields_checked());
+
+			if (should_accept_remote(accept, decoded_name, decoded_url,
+						 &extras, info_list))
+				strvec_push(accepted, decoded_name);
+		}
 
+		string_list_clear(&extras, 0);
 		strbuf_list_free(elems);
 		free(decoded_name);
 		free(decoded_url);
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
index 26f3c63112..858b34587d 100755
--- a/t/t5710-promisor-remote-capability.sh
+++ b/t/t5710-promisor-remote-capability.sh
@@ -321,6 +321,41 @@ test_expect_success "clone with promisor.sendExtraFields" '
 	check_missing_objects server 1 "$oid"
 '
 
+test_expect_success "clone with promisor.checkExtraFields" '
+	git -C server config promisor.advertise true &&
+	test_when_finished "rm -rf client" &&
+
+	git -C server remote add otherLop "https://invalid.invalid"  &&
+	git -C server config remote.otherLop.id "fooBar" &&
+	git -C server config remote.otherLop.stuff "baz" &&
+	git -C server config remote.otherLop.partialCloneFilter "blob:limit=10k" &&
+	test_when_finished "git -C server remote remove otherLop" &&
+	git -C server config promisor.sendExtraFields "id, partialCloneFilter" &&
+	test_when_finished "git -C server config unset promisor.sendExtraFields" &&
+	test_when_finished "rm trace" &&
+
+	# Clone from server to create a client
+	GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
+		-c remote.lop.promisor=true \
+		-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
+		-c remote.lop.url="file://$(pwd)/lop" \
+		-c remote.lop.partialCloneFilter="blob:none" \
+		-c promisor.acceptfromserver=All \
+		-c promisor.checkExtraFields=partialCloneFilter \
+		--no-local --filter="blob:limit=5k" server client &&
+
+	# Check that extra fields are properly transmitted
+	ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") &&
+	PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" &&
+	PR2="name=otherLop,url=https://invalid.invalid,id=fooBar,partialCloneFilter=blob:limit=10k" &&
+	test_grep "clone< promisor-remote=$PR1;$PR2" trace &&
+	test_grep "clone> promisor-remote=lop" trace &&
+	test_grep ! "clone> promisor-remote=lop;otherLop" trace &&
+
+	# Check that the largest object is still missing on the server
+	check_missing_objects server 1 "$oid"
+'
+
 test_expect_success "clone with promisor.advertise set to 'true' but don't delete the client" '
 	git -C server config promisor.advertise true &&
 
-- 
2.49.0.158.g6ac6832dc3.dirty


  parent reply	other threads:[~2025-04-14 16:04 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-14 16:03 [PATCH 0/4] Make the "promisor-remote" capability support extra fields Christian Couder
2025-04-14 16:03 ` [PATCH 1/4] config: move is_config_key_char() to "config.h" Christian Couder
2025-04-14 16:03 ` [PATCH 2/4] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-04-22 10:13   ` Patrick Steinhardt
2025-04-29 15:12     ` Christian Couder
2025-04-14 16:03 ` [PATCH 3/4] promisor-remote: allow a server to advertise extra fields Christian Couder
2025-04-14 22:04   ` Junio C Hamano
2025-04-22 10:13     ` Patrick Steinhardt
2025-04-29 15:12       ` Christian Couder
2025-04-29 15:12     ` Christian Couder
2025-04-14 16:03 ` Christian Couder [this message]
2025-04-29 14:52 ` [PATCH v2 0/3] Make the "promisor-remote" capability support more fields Christian Couder
2025-04-29 14:52   ` [PATCH v2 1/3] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-05-07  8:25     ` Patrick Steinhardt
2025-05-19 14:10       ` Christian Couder
2025-05-07 12:27     ` Karthik Nayak
2025-05-19 14:10       ` Christian Couder
2025-04-29 14:52   ` [PATCH v2 2/3] promisor-remote: allow a server to advertise more fields Christian Couder
2025-05-07  8:25     ` Patrick Steinhardt
2025-05-19 14:11       ` Christian Couder
2025-05-27  7:50         ` Patrick Steinhardt
2025-05-27 15:30           ` Junio C Hamano
2025-06-11 13:46           ` Christian Couder
2025-05-07 12:44     ` Karthik Nayak
2025-05-19 14:11       ` Christian Couder
2025-04-29 14:52   ` [PATCH v2 3/3] promisor-remote: allow a client to check fields Christian Couder
2025-05-07  8:25     ` Patrick Steinhardt
2025-05-19 14:11       ` Christian Couder
2025-05-02  9:34   ` [PATCH v2 0/3] Make the "promisor-remote" capability support more fields Christian Couder
2025-05-19 14:12   ` [PATCH v3 0/5] " Christian Couder
2025-05-19 14:12     ` [PATCH v3 1/5] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-05-20  9:37       ` Karthik Nayak
2025-05-20 13:32         ` Christian Couder
2025-05-20 16:45           ` Junio C Hamano
2025-05-21  6:33             ` Christian Couder
2025-05-21 15:00               ` Junio C Hamano
2025-06-11 13:47                 ` Christian Couder
2025-05-19 14:12     ` [PATCH v3 2/5] promisor-remote: allow a server to advertise more fields Christian Couder
2025-05-21 20:31       ` Justin Tobler
2025-06-11 13:46         ` Christian Couder
2025-05-27  7:51       ` Patrick Steinhardt
2025-06-11 13:46         ` Christian Couder
2025-05-19 14:12     ` [PATCH v3 3/5] promisor-remote: refactor how we parse advertised fields Christian Couder
2025-05-19 14:12     ` [PATCH v3 4/5] promisor-remote: allow a client to check fields Christian Couder
2025-05-19 14:12     ` [PATCH v3 5/5] promisor-remote: use string constants for 'name' and 'url' too Christian Couder
2025-06-11 13:45     ` [PATCH v4 0/5] Make the "promisor-remote" capability support more fields Christian Couder
2025-06-11 13:45       ` [PATCH v4 1/5] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-06-19 11:53         ` Karthik Nayak
2025-06-25 12:53           ` Christian Couder
2025-06-23 19:38         ` Justin Tobler
2025-06-25 12:52           ` Christian Couder
2025-06-11 13:45       ` [PATCH v4 2/5] promisor-remote: allow a server to advertise more fields Christian Couder
2025-06-19 12:15         ` Karthik Nayak
2025-06-25 12:51           ` Christian Couder
2025-06-23 19:59         ` Justin Tobler
2025-06-25 12:51           ` Christian Couder
2025-06-11 13:45       ` [PATCH v4 3/5] promisor-remote: refactor how we parse advertised fields Christian Couder
2025-06-11 13:45       ` [PATCH v4 4/5] promisor-remote: allow a client to check fields Christian Couder
2025-06-11 13:45       ` [PATCH v4 5/5] promisor-remote: use string constants for 'name' and 'url' too Christian Couder
2025-06-19 12:18       ` [PATCH v4 0/5] Make the "promisor-remote" capability support more fields Karthik Nayak
2025-06-25 12:50       ` [PATCH v5 " Christian Couder
2025-06-25 12:50         ` [PATCH v5 1/5] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-06-25 17:05           ` Junio C Hamano
2025-07-21 14:08             ` Christian Couder
2025-06-25 12:50         ` [PATCH v5 2/5] promisor-remote: allow a server to advertise more fields Christian Couder
2025-06-25 22:29           ` Junio C Hamano
2025-07-21 14:09             ` Christian Couder
2025-07-21 18:53               ` Junio C Hamano
2025-07-31  7:20                 ` Christian Couder
2025-06-27 18:47           ` Jean-Noël Avila
2025-07-21 14:09             ` Christian Couder
2025-06-25 12:50         ` [PATCH v5 3/5] promisor-remote: refactor how we parse advertised fields Christian Couder
2025-06-25 12:50         ` [PATCH v5 4/5] promisor-remote: allow a client to check fields Christian Couder
2025-06-25 12:50         ` [PATCH v5 5/5] promisor-remote: use string constants for 'name' and 'url' too Christian Couder
2025-07-07 22:35         ` [PATCH v5 0/5] Make the "promisor-remote" capability support more fields Junio C Hamano
2025-07-08  3:34           ` Christian Couder
2025-07-21 14:10         ` [PATCH v6 " Christian Couder
2025-07-21 14:10           ` [PATCH v6 1/5] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-07-21 14:10           ` [PATCH v6 2/5] promisor-remote: allow a server to advertise more fields Christian Couder
2025-07-21 14:10           ` [PATCH v6 3/5] promisor-remote: refactor how we parse advertised fields Christian Couder
2025-07-21 20:39             ` Junio C Hamano
2025-07-31  7:22               ` Christian Couder
2025-07-21 14:10           ` [PATCH v6 4/5] promisor-remote: allow a client to check fields Christian Couder
2025-07-21 20:59             ` Junio C Hamano
2025-07-31  7:21               ` Christian Couder
2025-07-21 14:10           ` [PATCH v6 5/5] promisor-remote: use string constants for 'name' and 'url' too Christian Couder
2025-07-21 20:18             ` Junio C Hamano
2025-07-31  7:23           ` [PATCH v7 0/5] Make the "promisor-remote" capability support more fields Christian Couder
2025-07-31  7:23             ` [PATCH v7 1/5] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-07-31  7:23             ` [PATCH v7 2/5] promisor-remote: allow a server to advertise more fields Christian Couder
2025-07-31  7:23             ` [PATCH v7 3/5] promisor-remote: refactor how we parse advertised fields Christian Couder
2025-07-31 16:03               ` Junio C Hamano
2025-09-08  5:31                 ` Christian Couder
2025-07-31  7:23             ` [PATCH v7 4/5] promisor-remote: allow a client to check fields Christian Couder
2025-07-31  7:23             ` [PATCH v7 5/5] promisor-remote: use string constants for 'name' and 'url' too Christian Couder
2025-07-31 15:48             ` [PATCH v7 0/5] Make the "promisor-remote" capability support more fields Junio C Hamano
2025-08-28 23:32             ` Junio C Hamano
2025-09-08  5:36               ` Christian Couder
2025-09-08  5:30             ` [PATCH v8 0/7] " Christian Couder
2025-09-08  5:30               ` [PATCH v8 1/7] promisor-remote: refactor to get rid of 'struct strvec' Christian Couder
2025-09-08  5:30               ` [PATCH v8 2/7] promisor-remote: allow a server to advertise more fields Christian Couder
2025-09-08  5:30               ` [PATCH v8 3/7] promisor-remote: use string constants for 'name' and 'url' too Christian Couder
2025-09-08  5:30               ` [PATCH v8 4/7] promisor-remote: refactor how we parse advertised fields Christian Couder
2025-09-08  5:30               ` [PATCH v8 5/7] promisor-remote: use string_list_split() in filter_promisor_remote() Christian Couder
2025-09-08  5:30               ` [PATCH v8 6/7] promisor-remote: allow a client to check fields Christian Couder
2025-09-08  5:30               ` [PATCH v8 7/7] promisor-remote: use string_list_split() in mark_remotes_as_accepted() Christian Couder
2025-09-08 17:34               ` [PATCH v8 0/7] Make the "promisor-remote" capability support more fields Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250414160343.2216312-5-christian.couder@gmail.com \
    --to=christian.couder@gmail.com \
    --cc=chriscool@tuxfamily.org \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=karthik.188@gmail.com \
    --cc=me@ttaylorr.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).