Files
buildkit/util/gitutil/git_cli_test.go
MohammadHasan Akbari 8086fae369 gitutil: preserve SUDO_UID for git subprocesses
When git runs as root under sudo it consults SUDO_UID to decide whether a
repository's ownership can be trusted, additionally granting access to
repositories owned by the user who invoked sudo. GitCLI builds a
restricted environment for the git subprocess and did not forward
SUDO_UID, so commands such as `sudo docker build` tripped git's "detected
dubious ownership" check and silently lost commit provenance: the build
still succeeds but prints "current commit information was not captured by
the build".

Forward SUDO_UID (only when present) on the host git config path enabled
via WithHostGitConfig, i.e. client-side local git inspection. The default
isolated path used by daemon-side callers is left untouched so it does not
pick up host environment. This matches git's own default behavior under
sudo: it does not disable safe.directory checks and is not equivalent to
safe.directory=*; it merely lets git trust repositories owned by the
invoking user. Only SUDO_UID is forwarded (git's ownership check is
uid-based and never consults SUDO_GID).

Fixes the root cause for docker/buildx#3855. buildx inspects the build
context through this GitCLI with WithHostGitConfig enabled, so buildx
picks the fix up via a moby/buildkit dependency bump with no buildx-side
code change.

Signed-off-by: MohammadHasan Akbari <jarqvi.jarqvi@gmail.com>
2026-06-18 10:28:08 +04:00

72 lines
2.4 KiB
Go

package gitutil
import (
"context"
"os"
"os/exec"
"testing"
"github.com/stretchr/testify/require"
)
func TestGetGitSSHCommandUsesConfigPath(t *testing.T) {
cmd := getGitSSHCommand("")
require.Equal(t, "ssh -F "+os.DevNull+" -o StrictHostKeyChecking=no", cmd)
cmd = getGitSSHCommand("/known-hosts")
require.Equal(t, "ssh -F "+os.DevNull+" -o UserKnownHostsFile=/known-hosts", cmd)
}
func TestGitCLIConfigEnv(t *testing.T) {
t.Setenv("HOME", "/tmp/home")
t.Setenv("XDG_CONFIG_HOME", "/tmp/xdg")
t.Setenv("USERPROFILE", `C:\Users\tester`)
t.Setenv("HOMEDRIVE", "C:")
t.Setenv("HOMEPATH", `\Users\tester`)
t.Setenv("GIT_CONFIG_GLOBAL", "/tmp/global-gitconfig")
t.Setenv("GIT_CONFIG_SYSTEM", "/tmp/system-gitconfig")
t.Setenv("SUDO_UID", "1000")
t.Run("isolated by default", func(t *testing.T) {
var got []string
cli := NewGitCLI(WithExec(func(ctx context.Context, cmd *exec.Cmd) error {
got = append([]string(nil), cmd.Env...)
return nil
}))
_, 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.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")
require.NotContains(t, got, "GIT_CONFIG_SYSTEM=/tmp/system-gitconfig")
require.NotContains(t, got, "SUDO_UID=1000")
})
t.Run("host git config opt-in", func(t *testing.T) {
var got []string
cli := NewGitCLI(
WithHostGitConfig(),
WithExec(func(ctx context.Context, cmd *exec.Cmd) error {
got = append([]string(nil), cmd.Env...)
return nil
}),
)
_, 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.Contains(t, got, "HOME=/tmp/home")
require.Contains(t, got, "XDG_CONFIG_HOME=/tmp/xdg")
require.Contains(t, got, `USERPROFILE=C:\Users\tester`)
require.Contains(t, got, "HOMEDRIVE=C:")
require.Contains(t, got, `HOMEPATH=\Users\tester`)
require.Contains(t, got, "GIT_CONFIG_GLOBAL=/tmp/global-gitconfig")
require.Contains(t, got, "GIT_CONFIG_SYSTEM=/tmp/system-gitconfig")
require.Contains(t, got, "SUDO_UID=1000")
})
}