Skip to content

Commit

Permalink
safe.directory: allow "lead/ing/path/*" match
Browse files Browse the repository at this point in the history
When safe.directory was introduced in v2.30.3 timeframe, 8959555
(setup_git_directory(): add an owner check for the top-level
directory, 2022-03-02), it only allowed specific opt-out
directories.  Immediately after an embargoed release that included
the change, 0f85c4a (setup: opt-out of check with safe.directory=*,
2022-04-13) was done as a response to loosen the check so that a
single '*' can be used to say "I trust all repositories" for folks
who host too many repositories to list individually.

Let's further loosen the check to allow people to say "everything
under this hierarchy is deemed safe" by specifying such a leading
directory with "/*" appended to it.

Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
gitster committed May 29, 2024
1 parent 786a3e4 commit 313eec1
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 8 deletions.
3 changes: 2 additions & 1 deletion Documentation/config/safe.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ string `*`. This will allow all repositories to be treated as if their
directory was listed in the `safe.directory` list. If `safe.directory=*`
is set in system config and you want to re-enable this protection, then
initialize your list with an empty value before listing the repositories
that you deem safe.
that you deem safe. Giving a directory with `/*` appended to it will
allow access to all repositories under the named directory.
+
As explained, Git only allows you to access repositories owned by
yourself, i.e. the user who is running Git, by default. When Git
Expand Down
22 changes: 15 additions & 7 deletions setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1176,13 +1176,21 @@ static int safe_directory_cb(const char *key, const char *value,
} else if (!strcmp(value, "*")) {
data->is_safe = 1;
} else {
const char *interpolated = NULL;

if (!git_config_pathname(&interpolated, key, value) &&
!fspathcmp(data->path, interpolated ? interpolated : value))
data->is_safe = 1;

free((char *)interpolated);
const char *allowed = NULL;

if (!git_config_pathname(&allowed, key, value)) {
if (!allowed)
allowed = value;
if (ends_with(allowed, "/*")) {
size_t len = strlen(allowed);
if (!fspathncmp(allowed, data->path, len - 1))
data->is_safe = 1;
} else if (!fspathcmp(data->path, allowed)) {
data->is_safe = 1;
}
}
if (allowed != value)
free((char *)allowed);
}

return 0;
Expand Down
15 changes: 15 additions & 0 deletions t/t0033-safe-directory.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,22 @@ test_expect_success 'safe.directory=*, but is reset' '
expect_rejected_dir
'

test_expect_success 'safe.directory with matching glob' '
git config --global --unset-all safe.directory &&
p=$(pwd) &&
git config --global safe.directory "${p%/*}/*" &&
git status
'

test_expect_success 'safe.directory with unmatching glob' '
git config --global --unset-all safe.directory &&
p=$(pwd) &&
git config --global safe.directory "${p%/*}no/*" &&
expect_rejected_dir
'

test_expect_success 'safe.directory in included file' '
git config --global --unset-all safe.directory &&
cat >gitconfig-include <<-EOF &&
[safe]
directory = "$(pwd)"
Expand Down

0 comments on commit 313eec1

Please sign in to comment.