Skip to content

safe.bareRepository: default to "explicit" with WITH_BREAKING_CHANGES#2072

Open
dscho wants to merge 46 commits intogitgitgadget:masterfrom
dscho:make-safe.bareRepositories-the-default-in-git-3.0
Open

safe.bareRepository: default to "explicit" with WITH_BREAKING_CHANGES#2072
dscho wants to merge 46 commits intogitgitgadget:masterfrom
dscho:make-safe.bareRepositories-the-default-in-git-3.0

Conversation

@dscho
Copy link
Copy Markdown
Member

@dscho dscho commented Mar 24, 2026

In one of my projects, I work exclusively on bare repositories. During one of the tests, I noticed that safe.bareRepository is not yet enabled by default. This strikes me as undesirable, and I deem Git v3.0 the most logical opportunity to change the default.

Cc: Patrick Steinhardt ps@pks.im

@dscho dscho self-assigned this Mar 24, 2026
@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from 54b6c08 to a30a801 Compare March 27, 2026 17:31
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Mar 27, 2026

There are issues in commit 8365979:
infra: test-lib-functions and test-tool --git-dir

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Mar 27, 2026

There are issues in commit 9d4fafe:
category-H

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Mar 27, 2026

There are issues in commit 9d973bb:
category-L

  • Commit checks stopped - the message is too short
  • Commit not signed off

@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from a30a801 to 56cd924 Compare March 31, 2026 15:36
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Mar 31, 2026

The pull request has 46 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Mar 31, 2026

There are merge commits in this Pull Request:

ba5445cb20655869b2b744bd1b89aeaa6af3b8e3
e956f0d154c8d3b77a28d993dbd7562ed5bfe490
f14f6f9b60d620526b608ab2a0c79a0a61153ceb
865f2382894d58d8e242cd31d635d5e0cdd2bfb3
cc4055b1baa340f53c478c495ee25cb10bcec571
abc24c6ba7ba294bfcf38ace54e37fe4b3d96ea7
2ea73fd8150c6456032d96231bb7933dd9461ea5

Please rebase the branch and force-push.

@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from 56cd924 to d394f8c Compare April 1, 2026 08:26
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

The pull request has 45 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

There are merge commits in this Pull Request:

ce7336af6344b931357623aef8f620d5c009fc77
eab57787b4a2bf0d42c0052d180088044b3678b7
350fc99b47753b4753f2c6d24269dc1e78dceec3
29bf0a2e3320a80869be5d9fb4c8d2edea56bd89
057d9cc7ab7c80cd6d29e443c4266de9be6b7564
4c084d3bfc5497e4e97bb57780427c632c21ad91
d409f10f22ccf5ea040cd38391f5ad71a869bbb2

Please rebase the branch and force-push.

8d1a744 (setup.c: create `safe.bareRepository`, 2022-07-14)
introduced a setting to restrict implicit bare repository discovery,
mitigating a social-engineering attack where an embedded bare repo's
hooks get executed unknowingly. To allow for that default to change at
some stage in the future, the tests need to be prepared.

This commit adjusts a test accordingly that runs `git aliasedinit`
from inside a bare repo to verify that aliased commands work there.
The test is about alias resolution, not bare repo discovery, so add
`test_config_global safe.bareRepository all` to opt in explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from d394f8c to 027d941 Compare April 1, 2026 14:42
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

The pull request has 45 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

There are merge commits in this Pull Request:

aea930821685d3fc8e71ca6186bdaf99d5faa5b7
976d8e107ff7b83ce52e6ba900d0083450ad752d
d4498b8f5890f83edd2dbbccccae36a3aa27aa1d
32dfb79563a29afee0cfd8fd88407fe04dada36e
3e3bc200c6c321ca9125fbf42b849435a4de99cc
6d0858d901d164777fe59f85761deac45e27acfd

Please rebase the branch and force-push.

dscho added 10 commits April 1, 2026 18:41
To prepare for `safe.bareRepository` defaulting to `explicit`
(see 8d1a744), replace `cd <dir> && git config` with `git
--git-dir=<dir> config` so the helper does not rely on implicit bare
repository discovery.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The bare repo tests in t0003-attributes.sh currently `cd` into the bare
repository inside subshells, relying on implicit discovery. Restructure
these tests to pass `--git-dir=bare.git` to the `attr_check` and
`attr_check_source` helpers instead. This makes the code much easier to
read, and also makes bare repo access explicit, i.e. compatible with an
eventual `safe.bareRepository=explicit` default.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `git -C c/a.git --work-tree=../a` invocations in t0056-git-C.sh
enter what is technically the `.git` directory of a repository to
test `-C` combined with `--work-tree`. In doing so, the code relies on
implicit discovery of bare repositories, which 8d1a744 (setup.c:
create `safe.bareRepository`, 2022-07-14) prepared to be prevented by
default.

These tests verify the interaction between those flags, so changing them
to use `--git-dir` would defeat their purpose. So let's just temporarily
force-enable implicit discovery of bare repositories, no matter what
`safe.bareRepository` defaults to.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Replace an unnecessarily complex subshell pattern with a much simpler
`--git-dir`-based one. The latter is not only simpler, it also no
longer relies on implicit bare repo discovery, which would fail with
`safe.bareRepository=explicit`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
To prepare for `safe.bareRepository` defaulting to `explicit` (see
8d1a744), add an optional 6th parameter `repo_flag` (defaulting
to `-C`) to the `test_repo_info` helper, and use it in the caller that
wants to operate on a bare repository.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
To prepare for `safe.bareRepository` defaulting to `explicit` (see
8d1a744), specify the gitdir specifically in bare-repo `git
worktree add` invocations via `--git-dir=.` so Git does not rely on
implicit bare repository discovery.

While at it, also avoid unnecessary subshells and `cd`ing. This
simplifies the logic in a rather pleasant way.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
To prepare for `safe.bareRepository` defaulting to `explicit` (see
8d1a744), the test case t2406.10(repair .git file from bare.git)
cannot rely on the implicit discovery of thee bare repository. Simply
add a `--git-dir=.` to the invocation. The `-C bare.git` argument is
still needed so that the `repair` command realizes works on the intended
directory.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The test case "fetch specific OID with tag following" creates a bare
repository and wants to operate on it by changing the working directory
and relying on Git's implicit discovery of the bare repository.

Once the `safe.bareRepository` default is changed, this is no longer
an option.

So let's adjust the commands to specify the bare repository explicitly,
via `--git-dir`, and avoid changing the working directory. As a bonus,
the result is arguably more readable than the original code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
To prepare for `safe.bareRepository` defaulting to `explicit` (see
8d1a744), export `GIT_DIR=.` right after `git init --bare &&` so
subsequent commands access the bare repo explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
After switching from `-C pushee` to `--git-dir=pushee` as part of
the `safe.bareRepository` preparation, `ext::` URLs that used `.`
(resolved relative to the `-C` target) must spell out the directory
name explicitly.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from 027d941 to 7287728 Compare April 1, 2026 16:54
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

The pull request has 43 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

There are merge commits in this Pull Request:

ea3431d9ae77f422613b84e8d18c9a2e62623278
b031c40bfaab3b520f9b4134aedc9fe72dfc9b89
d27d135adc8f071e491b168d70d90ae3c01a8b65
543cc46db07dd5df04514d2619f30a93299ff315

Please rebase the branch and force-push.

@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from 7287728 to 6c246b0 Compare April 1, 2026 17:14
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

The pull request has 44 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

dscho added 8 commits April 1, 2026 22:10
Preparing for `safe.bareRepository` defaulting to `explicit` (see
8d1a744), change the `post_checkout_hook` helper from hard-coding
`test_hook -C "$1"` to forwarding all arguments via `test_hook "$@"`, so
callers can pass `--git-dir <dir>` for bare repos.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Preparing for `safe.bareRepository` defaulting to `explicit` (see
8d1a744), add `--git-dir` option parsing to `test_cmp_refs` in
t5411/common-functions.sh, parallel to the existing `-C` handling. When
given, the helper passes `--git-dir="$gitdir"` to `git show-ref`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
As part of the preparation for `safe.bareRepository` defaulting
to `explicit` (see 8d1a744), switch bare-repo calls from
`test_cmp_refs -C` to `test_cmp_refs --git-dir` in the t5411
proc-receive test files.

To make reviewing this commit easier, here is a command-line to undo the
transformation on the new lines; empty output is success:

    git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ { old[m++] = substr($0,2) }
      /^\+/ {
        new = substr($0,2)
        # undo: --git-dir -> -C
        gsub(/test_cmp_refs --git-dir /, "test_cmp_refs -C ", new)
        if (old[n++] != new) print old[n-1] " != " new
      }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from 6c246b0 to 8a98e1f Compare April 1, 2026 20:11
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

The pull request has 46 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 1, 2026

There are merge commits in this Pull Request:

01e3eb0864055250d77d094cb624be7e2ab659be
ffd5f4a698c3836d000e620834ab861b9db0b05b

Please rebase the branch and force-push.

dscho added 9 commits April 2, 2026 08:17
As part of the preparation for `safe.bareRepository` defaulting
to `explicit` (see 8d1a744), switch `test_hook ... -C` to
`test_hook ... --git-dir` for bare repos.

To verify this commit mechanically, here is an awk command-line that
undoes the transformation on the new lines; empty output is success:

    git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ { old[m++] = substr($0,2) }
      /^\+/ {
        new = substr($0,2)
        # undo: --git-dir -> -C
        gsub(/ --git-dir /, " -C ", new)
        if (old[n++] != new) print old[n-1] " != " new
      }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit replaces a couple of `-C <dir>` invocations where
`<dir>` is a bare repository with `--git-dir=<dir>` as part of the
`safe.bareRepository` preparation.

Since `--git-dir` does not change the working directory, paths that
duplicated the directory name as a prefix are now redundant.

This commit can be validated in a mechanical way via this command-line:

  git diff HEAD^! | awk '
    /^diff/,/^\+\+\+/ { next }
    /^-/ { old[m++] = substr($0, 2) }
    /^\+/ {
      line = substr($0,2)
      # apply: -C X -> --git-dir=X and strip ../
      if (match(line, /--git-dir=([^ ]*)(.* )([^ ]*)\//, a) &&
           a[1] == a[3]) {
        gsub(/--git-dir=.*\//, "-C " a[1] a[2], line)
      }
      if (old[n++] != line) print old[n-1] " != " line
    }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
To avoid having to rely on implicit discovery of bare repositories
(which will go away at some stage by flipping the default of
`safe.bareRepository`), this commit replaces `-C <dir>` with
`--git-dir=<dir>`. Since `--git-dir` does not change the working
directory, a `.` that formerly referred to the `-C` target must become
`..` to reach the same location.

The code changes can be validated via this command-line:

  git diff HEAD^! | awk '
    /^diff/,/^\+\+\+/ { next }
    /^-/ { old[m++] = substr($0, 2) }
    /^\+/ {
      line = substr($0,2)
      # apply: -C X -> --git-dir=X and strip ../
      if (match(line, /--git-dir=(.* )\. /, a)) {
        gsub(/--git-dir=.* \. /, "-C " a[1] ".. ", line)
      }
      if (old[n++] != line) print old[n-1] " != " line
    }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
There are quite a few tests that assume that the default of the
`safe.bareRepository` setting is that it allows discovery of bare
repositories. This is unsafe. To allow the default to change, this
commit tackles a couple of places in the test suite: By setting GIT_DIR
after changing the current working directory to the bare repository,
Git no longer needs to discover it, and by unsetting GIT_DIR as soon
as leaving said directory, Git once again returns to the regular
programming of discovering the `.git` directory.

This commit can be validated mechanically by running the following
command-line:

  git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ { old[m++] = substr($0,2) }
      /^\+/ {
        new = substr($0,2)
        # undo: strip GIT_DIR export
        gsub(/ GIT_DIR=[.] && export GIT_DIR &&/, "", new)
        # undo: strip sane_unset GIT_DIR
        gsub(/ && sane_unset GIT_DIR/, "", new)
        if (old[n++] != new) print old[n-1] " != " new
      }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The default of the `safe.bareRepository` will change at some stage, at
which time bare repositories won't be discovered implicitly in general
anymore.

When `git reset` is called with an explicit gitdir (e.g. by using the
`--git-dir` option), it behaves differently from an implicit gitdir,
though: In the former case, it trusts the user to know what they are
doing, in the latter case it will refuse certain modes because they
require a worktree. For that reason, we have to adjust the test cases
that verify this behavior not by specifying the gitdir explicitly, but
instead enforcing implicit gitdir discovery.

The test cases that want to verify that the Git prompt shows
`(GIT_DIR!)` when a gitdir was discovered implicitly _also_ need the
same treatment.

Mechanical verification of the code changes can be performed via this
here command-line (the awk script undoes the transformation on the new
lines; empty output is success):

    git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ { old[m++] = substr($0,2) }
      /^\+/ {
        new = substr($0,2)
        # undo: strip GIT_CONFIG_PARAMETERS and export
        gcp="GIT_CONFIG_PARAMETERS"
        gsub(" " gcp "=[^ ]* && export " gcp " &&", "", new)
        if (old[n++] != new) print old[n-1] " != " new
      }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
An easy way to prepare the tests for a time when the
`safe.bareRepository` default changes is to replace `-C <dir>` with
`--git-dir=<dir>` in those invocations that concern bare repositories.
However, in some cases, further adjustments are required: Since `-C`
changes the work directory, relative paths specified in the Git command
in parameters have to change, too.

This commit takes care of the `git -C <dir>` invocations that specify
paths in the current directory, via `../<name>` arguments. Naturally,
these arguments now need to drop that `../` prefix after no longer
changing the working directory.

This commit can be verified mechanically via this awk script that
applies the transformation on the old lines; empty output is success:

    git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ {
        line = substr($0,2)
        # apply: -C X -> --git-dir=X and strip ../
        if (match(line, /-C ([^ ]*)/, a)) {
          gsub(/-C [^ ]*/, "--git-dir=" a[1], line)
        }
        gsub(/\.\.\//, "", line)
        old[m++] = line
      }
      /^\+/ { new = substr($0,2); if (old[n++] != new) print old[n-1] " != " new }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
As part of the preparation for `safe.bareRepository` defaulting to
`explicit` (see 8d1a744), add `GIT_DIR=. && export GIT_DIR &&`
right after `cd <bare> &&` so that subsequent commands access the bare
repo explicitly rather than relying on implicit discovery.

Here is a command-line to help verify this commit mechanically (the
awk script undoes the transformation on the new lines; empty output
is success):

    git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ { old[m++] = substr($0,2) }
      /^\+/ {
        new = substr($0,2)
        # undo: strip GIT_DIR export
        gsub(/ && GIT_DIR=[.] && export GIT_DIR/, "", new)
        if (old[n++] != new) print old[n-1] " != " new
      }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from 8a98e1f to fe0c788 Compare April 2, 2026 06:18
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 2, 2026

The pull request has 46 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 2, 2026

There are merge commits in this Pull Request:

01e3eb0864055250d77d094cb624be7e2ab659be
ffd5f4a698c3836d000e620834ab861b9db0b05b

Please rebase the branch and force-push.

dscho added 3 commits April 2, 2026 08:56
As part of the preparation for `safe.bareRepository` defaulting to
`explicit` (see 8d1a744), replace `git -C <bare>` with `git
--git-dir=<bare>`. The `-C` flag triggers implicit bare repository
discovery, whereas `--git-dir` specifies the repository location
explicitly.

This commit can be verified mechanically by invoking this command-line
(the awk script undoes the transformation on the new lines; empty output
is success):

    git diff HEAD^! | awk '
      /^diff/,/^\+\+\+/ { next }
      /^-/ { old[m++] = substr($0,2) }
      /^\+/ {
        new = substr($0,2)
        # undo: --git-dir=X -> -C X
        if (match(new, /--git-dir=([^ ]*)/, a)) {
          gsub(/--git-dir=[^ ]*/, "-C " a[1], new)
        }
        if (old[n++] != new) print old[n-1] " != " new
      }'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
When an attacker can convince a user to clone a crafted repository
that contains an embedded bare repository with malicious hooks, any Git
command the user runs after entering that subdirectory will discover
the bare repository and execute the hooks. The user does not even need
to run a Git command explicitly: many shell prompts run `git status`
in the background to display branch and dirty state information, and
`git status` in turn may invoke the fsmonitor hook if so configured,
making the user vulnerable the moment they `cd` into the directory. The
`safe.bareRepository` configuration variable (introduced in 8959555
(setup_git_directory(): add an owner check for the top-level directory,
2022-03-02)) already provides protection against this attack vector by
allowing users to set it to "explicit", but the default remained "all"
for backwards compatibility.

Since Git 3.0 is the natural point to change defaults to safer
values, flip the default from "all" to "explicit" when built with
`WITH_BREAKING_CHANGES`. This means Git will refuse to work with bare
repositories that are discovered implicitly by walking up the directory
tree. Bare repositories specified via `--git-dir` or `GIT_DIR` continue
to work, and directories that look like `.git`, worktrees, or submodule
directories are unaffected (the existing `is_implicit_bare_repo()`
whitelist handles those cases).

Users who rely on implicit bare repository discovery can restore the
previous behavior by setting `safe.bareRepository=all` in their global
or system configuration.

The test for the "safe.bareRepository in the repository" scenario
needed a more involved fix: it writes a `safe.bareRepository=all`
entry into the bare repository's own config to verify that repo-local
config does not override the protected (global) setting. Previously,
`test_config -C` was used to write that entry, but its cleanup runs `git
-C <bare-repo> config --unset`, which itself fails when the default is
"explicit" and the global config has already been cleaned up. Switching
to direct git config --file access avoids going through repository
discovery entirely.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho force-pushed the make-safe.bareRepositories-the-default-in-git-3.0 branch from fe0c788 to bda3baf Compare April 2, 2026 06:57
@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 2, 2026

The pull request has 46 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

@gitgitgadget
Copy link
Copy Markdown

gitgitgadget bot commented Apr 2, 2026

There are merge commits in this Pull Request:

01e3eb0864055250d77d094cb624be7e2ab659be
ffd5f4a698c3836d000e620834ab861b9db0b05b

Please rebase the branch and force-push.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant