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>,
Elijah Newren <newren@gmail.com>,
Christian Couder <christian.couder@gmail.com>,
Christian Couder <chriscool@tuxfamily.org>
Subject: [PATCH v2 5/8] promisor-remote: introduce promisor.acceptFromServerUrl
Date: Mon, 27 Apr 2026 14:41:05 +0200 [thread overview]
Message-ID: <20260427124108.3524129-6-christian.couder@gmail.com> (raw)
In-Reply-To: <20260427124108.3524129-1-christian.couder@gmail.com>
The "promisor-remote" protocol capability allows servers to advertise
promisor remotes, but doesn't allow these remotes to be automatically
configured on the client.
Let's introduce a new `promisor.acceptFromServerUrl` config variable
which contains a glob pattern, so that advertised remotes with a URL
matching that pattern will be automatically configured.
The glob pattern can optionally be prefixed with a remote name which
will be used as the name of the new local remote.
For now though, let's only introduce the functions to read and validate
the glob patterns and the optional prefixes.
Checking if the URLs of the advertised remotes match the glob patterns
and taking the appropriate action is left for a following commit.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
promisor-remote.c | 90 +++++++++++++++++++++++++++
t/t5710-promisor-remote-capability.sh | 21 +++++++
2 files changed, 111 insertions(+)
diff --git a/promisor-remote.c b/promisor-remote.c
index 7699e259eb..3f3924f587 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -12,6 +12,7 @@
#include "packfile.h"
#include "environment.h"
#include "url.h"
+#include "urlmatch.h"
#include "version.h"
struct promisor_remote_config {
@@ -657,6 +658,90 @@ static bool has_control_char(const char *s)
return false;
}
+struct allowed_url {
+ char *remote_name;
+ char *url_pattern;
+ struct url_info pattern_info;
+};
+
+static void allowed_url_free(void *util, const char *str UNUSED)
+{
+ struct allowed_url *allowed = util;
+
+ if (!allowed)
+ return;
+
+ /* Depending on prefix, free either remote_name or url_pattern */
+ free(allowed->remote_name ? allowed->remote_name : allowed->url_pattern);
+ free(allowed->pattern_info.url);
+ free(allowed);
+}
+
+static struct allowed_url *valid_accept_url(const char *url)
+{
+ char *dup, *p;
+ struct allowed_url *allowed;
+
+ if (!url)
+ return NULL;
+
+ dup = xstrdup(url);
+ p = strchr(dup, '=');
+ if (p) {
+ *p = '\0';
+ if (!valid_remote_name(dup)) {
+ warning(_("invalid remote name '%s' before '=' sign "
+ "in '%s' from promisor.acceptFromServerUrl config"),
+ dup, url);
+ free(dup);
+ return NULL;
+ }
+ p++;
+ } else {
+ p = dup;
+ }
+
+ if (has_control_char(p)) {
+ warning(_("invalid url pattern '%s' "
+ "in '%s' from promisor.acceptFromServerUrl config"), p, url);
+ free(dup);
+ return NULL;
+ }
+
+ allowed = xmalloc(sizeof(*allowed));
+ allowed->remote_name = (p == dup) ? NULL : dup;
+ allowed->url_pattern = p;
+ allowed->pattern_info.url = url_normalize_pattern(p, &allowed->pattern_info);
+ if (!allowed->pattern_info.url) {
+ warning(_("invalid url pattern '%s' "
+ "in '%s' from promisor.acceptFromServerUrl config"), p, url);
+ free(dup);
+ free(allowed);
+ return NULL;
+ }
+
+ return allowed;
+}
+
+static void load_accept_from_server_url(struct repository *repo,
+ struct string_list *accept_urls)
+{
+ const struct string_list *config_urls;
+
+ if (!repo_config_get_string_multi(repo, "promisor.acceptfromserverurl", &config_urls)) {
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, config_urls) {
+ struct allowed_url *allowed = valid_accept_url(item->string);
+ if (allowed) {
+ struct string_list_item *new;
+ new = string_list_append(accept_urls, item->string);
+ new->util = allowed;
+ }
+ }
+ }
+}
+
static int should_accept_remote(enum accept_promisor accept,
struct promisor_info *advertised,
struct string_list *config_info)
@@ -901,6 +986,10 @@ static void filter_promisor_remote(struct repository *repo,
struct string_list_item *item;
bool reload_config = false;
enum accept_promisor accept = accept_from_server(repo);
+ struct string_list accept_urls = STRING_LIST_INIT_DUP;
+
+ /* Load and validate the acceptFromServerUrl config */
+ load_accept_from_server_url(repo, &accept_urls);
if (accept == ACCEPT_NONE)
return;
@@ -934,6 +1023,7 @@ static void filter_promisor_remote(struct repository *repo,
}
}
+ string_list_clear_func(&accept_urls, allowed_url_free);
promisor_info_list_clear(&config_info);
string_list_clear(&remote_info, 0);
store_info_free(store_info);
diff --git a/t/t5710-promisor-remote-capability.sh b/t/t5710-promisor-remote-capability.sh
index bf1cc54605..3b39505380 100755
--- a/t/t5710-promisor-remote-capability.sh
+++ b/t/t5710-promisor-remote-capability.sh
@@ -387,6 +387,27 @@ test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" '
check_missing_objects server 1 "$oid"
'
+test_expect_success "clone with invalid promisor.acceptFromServerUrl" '
+ git -C server config promisor.advertise true &&
+ test_when_finished "rm -rf client" &&
+
+ # As "bad name" contains a space, which is not a valid remote name,
+ # the pattern should be rejected with a warning and no remote created.
+ GIT_NO_LAZY_FETCH=0 git clone \
+ -c promisor.acceptfromserver=None \
+ -c "promisor.acceptFromServerUrl=bad name=https://example.com/*" \
+ --no-local --filter="blob:limit=5k" server client 2>err &&
+
+ # Check that a warning was emitted
+ test_grep "invalid remote name '\''bad name'\''" err &&
+
+ # Check that the largest object is not missing on the server
+ check_missing_objects server 0 "" &&
+
+ # Reinitialize server so that the largest object is missing again
+ initialize_server 1 "$oid"
+'
+
test_expect_success "clone with promisor.sendFields" '
git -C server config promisor.advertise true &&
test_when_finished "rm -rf client" &&
--
2.54.0.19.gb68b9497aa
next prev parent reply other threads:[~2026-04-27 12:41 UTC|newest]
Thread overview: 80+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-23 11:11 [PATCH 0/9] Implement `promisor.storeFields` and `--filter=auto` Christian Couder
2025-12-23 11:11 ` [PATCH 1/9] promisor-remote: refactor initialising field lists Christian Couder
2025-12-23 11:11 ` [PATCH 2/9] promisor-remote: allow a client to store fields Christian Couder
2026-01-07 10:05 ` Patrick Steinhardt
2026-02-04 10:20 ` Christian Couder
2025-12-23 11:11 ` [PATCH 3/9] clone: make filter_options local to cmd_clone() Christian Couder
2025-12-23 11:11 ` [PATCH 4/9] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-01-07 10:05 ` Patrick Steinhardt
2025-12-23 11:11 ` [PATCH 5/9] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2025-12-26 13:33 ` Jean-Noël AVILA
2026-02-04 11:19 ` Christian Couder
2025-12-23 11:11 ` [PATCH 6/9] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-01-07 10:05 ` Patrick Steinhardt
2026-02-04 10:21 ` Christian Couder
2025-12-23 11:11 ` [PATCH 7/9] list-objects-filter-options: implement auto filter resolution Christian Couder
2026-01-07 10:05 ` Patrick Steinhardt
2026-02-04 10:29 ` Christian Couder
2026-02-11 11:48 ` Patrick Steinhardt
2026-02-12 10:07 ` Christian Couder
2025-12-23 11:11 ` [PATCH 8/9] promisor-remote: keep advertised filter in memory Christian Couder
2026-01-07 10:05 ` Patrick Steinhardt
2026-02-04 10:57 ` Christian Couder
2026-02-11 11:48 ` Patrick Steinhardt
2026-02-11 16:59 ` Junio C Hamano
2026-02-12 10:07 ` Christian Couder
2025-12-23 11:11 ` [PATCH 9/9] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-01-07 10:05 ` Patrick Steinhardt
2026-02-04 11:06 ` Christian Couder
2026-02-04 11:08 ` [PATCH v2 0/8] Implement `promisor.storeFields` and `--filter=auto` Christian Couder
2026-02-04 11:08 ` [PATCH v2 1/8] promisor-remote: refactor initialising field lists Christian Couder
2026-02-04 11:08 ` [PATCH v2 2/8] promisor-remote: allow a client to store fields Christian Couder
2026-02-04 11:08 ` [PATCH v2 3/8] clone: make filter_options local to cmd_clone() Christian Couder
2026-02-04 11:08 ` [PATCH v2 4/8] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-02-04 11:08 ` [PATCH v2 5/8] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2026-02-11 11:48 ` Patrick Steinhardt
2026-02-12 10:06 ` Christian Couder
2026-02-04 11:08 ` [PATCH v2 6/8] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-02-04 11:08 ` [PATCH v2 7/8] promisor-remote: keep advertised filters in memory Christian Couder
2026-02-04 11:08 ` [PATCH v2 8/8] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-02-11 11:48 ` Patrick Steinhardt
2026-02-12 10:07 ` Christian Couder
2026-02-12 10:08 ` [PATCH v3 0/9] Implement `promisor.storeFields` and `--filter=auto` Christian Couder
2026-02-12 10:08 ` [PATCH v3 1/9] promisor-remote: refactor initialising field lists Christian Couder
2026-02-12 10:08 ` [PATCH v3 2/9] promisor-remote: allow a client to store fields Christian Couder
2026-02-12 10:08 ` [PATCH v3 3/9] clone: make filter_options local to cmd_clone() Christian Couder
2026-02-12 10:08 ` [PATCH v3 4/9] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-02-12 10:08 ` [PATCH v3 5/9] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2026-02-12 10:08 ` [PATCH v3 6/9] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-02-14 2:35 ` Jeff King
2026-02-16 13:26 ` Christian Couder
2026-02-12 10:08 ` [PATCH v3 7/9] promisor-remote: keep advertised filters in memory Christian Couder
2026-02-12 10:08 ` [PATCH v3 8/9] promisor-remote: change promisor_remote_reply()'s signature Christian Couder
2026-02-13 11:25 ` Patrick Steinhardt
2026-02-12 10:08 ` [PATCH v3 9/9] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-02-13 11:26 ` Patrick Steinhardt
2026-02-13 11:26 ` [PATCH v3 0/9] Implement `promisor.storeFields` and `--filter=auto` Patrick Steinhardt
2026-02-16 13:23 ` [PATCH v4 " Christian Couder
2026-02-16 13:23 ` [PATCH v4 1/9] promisor-remote: refactor initialising field lists Christian Couder
2026-02-16 13:23 ` [PATCH v4 2/9] promisor-remote: allow a client to store fields Christian Couder
2026-02-16 13:23 ` [PATCH v4 3/9] clone: make filter_options local to cmd_clone() Christian Couder
2026-02-16 13:23 ` [PATCH v4 4/9] fetch: make filter_options local to cmd_fetch() Christian Couder
2026-02-16 13:23 ` [PATCH v4 5/9] doc: fetch: document `--filter=<filter-spec>` option Christian Couder
2026-02-16 13:23 ` [PATCH v4 6/9] list-objects-filter-options: support 'auto' mode for --filter Christian Couder
2026-02-16 13:23 ` [PATCH v4 7/9] promisor-remote: keep advertised filters in memory Christian Couder
2026-02-16 13:23 ` [PATCH v4 8/9] promisor-remote: change promisor_remote_reply()'s signature Christian Couder
2026-02-16 13:23 ` [PATCH v4 9/9] fetch-pack: wire up and enable auto filter logic Christian Couder
2026-04-27 12:41 ` [PATCH v2 0/8] Auto-configure advertised remotes via URL allowlist Christian Couder
2026-04-27 12:41 ` [PATCH v2 1/8] t5710: simplify 'mkdir X' followed by 'git -C X init' Christian Couder
2026-04-27 12:41 ` [PATCH v2 2/8] urlmatch: change 'allow_globs' arg to bool Christian Couder
2026-04-27 12:41 ` [PATCH v2 3/8] urlmatch: add url_normalize_pattern() helper Christian Couder
2026-04-27 12:41 ` [PATCH v2 4/8] promisor-remote: add 'local_name' to 'struct promisor_info' Christian Couder
2026-05-04 11:46 ` Toon Claes
2026-04-27 12:41 ` Christian Couder [this message]
2026-04-27 12:41 ` [PATCH v2 6/8] promisor-remote: trust known remotes matching acceptFromServerUrl Christian Couder
2026-05-08 12:45 ` Toon Claes
2026-05-11 13:10 ` Toon Claes
2026-04-27 12:41 ` [PATCH v2 7/8] promisor-remote: auto-configure unknown remotes Christian Couder
2026-05-11 13:06 ` Toon Claes
2026-04-27 12:41 ` [PATCH v2 8/8] doc: promisor: improve acceptFromServer entry Christian Couder
2026-04-27 13:00 ` [PATCH v2 0/8] Auto-configure advertised remotes via URL allowlist Christian Couder
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=20260427124108.3524129-6-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=newren@gmail.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