diff --git a/util/gitutil/git_cli.go b/util/gitutil/git_cli.go index ebfe5fd7b4ae..a4c94c7b3553 100644 --- a/util/gitutil/git_cli.go +++ b/util/gitutil/git_cli.go @@ -219,9 +219,9 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error } } else { cmd.Env = append(cmd.Env, - "GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. - "HOME="+os.DevNull, // Disable reading from user gitconfig. - "GIT_CONFIG_GLOBAL="+os.DevNull, // Disable reading from global gitconfig. + "GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. + "HOME="+noConfigHome(), // Disable reading from user gitconfig. + "GIT_CONFIG_GLOBAL="+noConfigGlobal(), // Disable reading from global gitconfig. ) } for _, ev := range proxyEnvVars { diff --git a/util/gitutil/git_cli_test.go b/util/gitutil/git_cli_test.go index 23d3b98b77c4..9ebe88a86873 100644 --- a/util/gitutil/git_cli_test.go +++ b/util/gitutil/git_cli_test.go @@ -35,8 +35,8 @@ func TestGitCLIConfigEnv(t *testing.T) { _, err := cli.Run(context.Background(), "status") require.NoError(t, err) require.Contains(t, got, "GIT_CONFIG_NOSYSTEM=1") - require.Contains(t, got, "HOME="+os.DevNull) - require.Contains(t, got, "GIT_CONFIG_GLOBAL="+os.DevNull) + require.Contains(t, got, "HOME="+noConfigHome()) + require.Contains(t, got, "GIT_CONFIG_GLOBAL="+noConfigGlobal()) require.NotContains(t, got, "HOME=/tmp/home") require.NotContains(t, got, "XDG_CONFIG_HOME=/tmp/xdg") require.NotContains(t, got, "GIT_CONFIG_GLOBAL=/tmp/global-gitconfig") @@ -55,8 +55,8 @@ func TestGitCLIConfigEnv(t *testing.T) { _, err := cli.Run(context.Background(), "status") require.NoError(t, err) require.NotContains(t, got, "GIT_CONFIG_NOSYSTEM=1") - require.NotContains(t, got, "HOME="+os.DevNull) - require.NotContains(t, got, "GIT_CONFIG_GLOBAL="+os.DevNull) + require.NotContains(t, got, "HOME="+noConfigHome()) + require.NotContains(t, got, "GIT_CONFIG_GLOBAL="+noConfigGlobal()) require.Contains(t, got, "HOME=/tmp/home") require.Contains(t, got, "XDG_CONFIG_HOME=/tmp/xdg") require.Contains(t, got, `USERPROFILE=C:\Users\tester`) diff --git a/util/gitutil/git_noconfig_unix.go b/util/gitutil/git_noconfig_unix.go new file mode 100644 index 000000000000..8030eb24db78 --- /dev/null +++ b/util/gitutil/git_noconfig_unix.go @@ -0,0 +1,18 @@ +//go:build !windows + +package gitutil + +import "os" + +// noConfigHome returns a path to use for HOME that prevents git from +// reading user-level configuration. On Unix, /dev/null works because +// git silently fails to read /dev/null/.gitconfig. +func noConfigHome() string { + return os.DevNull +} + +// noConfigGlobal returns a path to use for GIT_CONFIG_GLOBAL that +// prevents git from reading the global gitconfig. +func noConfigGlobal() string { + return os.DevNull +} diff --git a/util/gitutil/git_noconfig_windows.go b/util/gitutil/git_noconfig_windows.go new file mode 100644 index 000000000000..8f1bf6c412b6 --- /dev/null +++ b/util/gitutil/git_noconfig_windows.go @@ -0,0 +1,47 @@ +//go:build windows + +package gitutil + +import ( + "os" + "path/filepath" + "sync" +) + +var ( + noConfigOnce sync.Once + noConfigDir string + noConfigFile string +) + +func initNoConfig() { + // On Windows ARM64, git cannot use the NUL device as HOME or a config + // path ("fatal: unable to access 'NUL': Invalid argument"). Create a + // temporary empty directory for HOME (so ~/.gitconfig is absent) and an + // empty file for GIT_CONFIG_GLOBAL. + dir, err := os.MkdirTemp("", "buildkit-git-noconfig") + if err != nil { + // Fallback: use os.DevNull (works on AMD64, may fail on ARM64). + noConfigDir = os.DevNull + noConfigFile = os.DevNull + return + } + noConfigDir = dir + noConfigFile = filepath.Join(dir, "empty-gitconfig") + // Best-effort create; an empty file is a valid (empty) gitconfig. + os.WriteFile(noConfigFile, nil, 0o600) +} + +// noConfigHome returns a path to use for HOME that prevents git from +// reading user-level configuration. +func noConfigHome() string { + noConfigOnce.Do(initNoConfig) + return noConfigDir +} + +// noConfigGlobal returns a path to use for GIT_CONFIG_GLOBAL that +// prevents git from reading the global gitconfig. +func noConfigGlobal() string { + noConfigOnce.Do(initNoConfig) + return noConfigFile +}