From 3124b3c839518a1c7d493751692688ca1bb77c4c Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:40:11 +0200 Subject: [PATCH 1/3] vendor: update buildkit to a243ce438aee Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 +- .../moby/buildkit/session/auth/auth.go | 4 +- .../moby/buildkit/util/gitutil/git_cli.go | 39 ++++++++++++++++--- vendor/modules.txt | 2 +- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 0347e1ab357d..12972ba426ed 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/hashicorp/hcl/v2 v2.24.0 github.com/in-toto/in-toto-golang v0.10.0 github.com/mitchellh/hashstructure/v2 v2.0.2 - github.com/moby/buildkit v0.29.0 + github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee github.com/moby/go-archive v0.2.0 github.com/moby/moby/api v1.54.1 github.com/moby/moby/client v0.4.0 diff --git a/go.sum b/go.sum index a66b821d6b1f..832e632554b2 100644 --- a/go.sum +++ b/go.sum @@ -420,8 +420,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/buildkit v0.29.0 h1:wxLEFbCOJntEDjSNNN2YWd8zxltZxT5muDQ0LzpbtpU= -github.com/moby/buildkit v0.29.0/go.mod h1:Dmv2FeDe34t75QuzeU87rBoZpAAkcpT5zeu4hXzmASc= +github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee h1:hA4wfynYJPaSnE4r1Ak5t/9goiG+OBKdQT29ZNxONrc= +github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee/go.mod h1:afndr4EIChUihZio6mhkfTePNtO6KOJh4qW7zOXHhW0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= diff --git a/vendor/github.com/moby/buildkit/session/auth/auth.go b/vendor/github.com/moby/buildkit/session/auth/auth.go index 232022ad23b2..a99c4904c0d5 100644 --- a/vendor/github.com/moby/buildkit/session/auth/auth.go +++ b/vendor/github.com/moby/buildkit/session/auth/auth.go @@ -25,10 +25,10 @@ func getSalt() []byte { return salt } -func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) { +func CredentialsFunc(ctx context.Context, sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) { return func(host string) (string, string, string, error) { var sessionID, user, secret string - err := sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error { + err := sm.Any(ctx, g, func(ctx context.Context, id string, c session.Caller) error { client := NewAuthClient(c.Conn()) resp, err := client.Credentials(ctx, &CredentialsRequest{ diff --git a/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go b/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go index 966e18ac45b2..ebfe5fd7b4ae 100644 --- a/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go +++ b/vendor/github.com/moby/buildkit/util/gitutil/git_cli.go @@ -27,6 +27,7 @@ type GitCLI struct { sshAuthSock string sshKnownHosts string + hostGitConfig bool } // Option provides a variadic option for configuring the git client. @@ -97,6 +98,15 @@ func WithSSHKnownHosts(sshKnownHosts string) Option { } } +// WithHostGitConfig allows git to read the host system and user git config. +// This is intended for client-side local git inspection. The default remains +// isolated so daemon-side callers do not leak host configuration into git. +func WithHostGitConfig() Option { + return func(b *GitCLI) { + b.hostGitConfig = true + } +} + type StreamFunc func(context.Context) (io.WriteCloser, io.WriteCloser, func()) // WithStreams configures a callback for getting the streams for a command. The @@ -108,7 +118,7 @@ func WithStreams(streams StreamFunc) Option { } } -// New initializes a new git client +// NewGitCLI initializes a new git client func NewGitCLI(opts ...Option) *GitCLI { c := &GitCLI{} for _, opt := range opts { @@ -191,9 +201,28 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error "GIT_TERMINAL_PROMPT=0", "GIT_SSH_COMMAND=" + getGitSSHCommand(cli.sshKnownHosts), // "GIT_TRACE=1", - "GIT_CONFIG_NOSYSTEM=1", // Disable reading from system gitconfig. - "HOME=/dev/null", // Disable reading from user gitconfig. - "LC_ALL=C", // Ensure consistent output. + "LC_ALL=C", // Ensure consistent output. + } + if cli.hostGitConfig { + for _, ev := range [...]string{ + "HOME", + "XDG_CONFIG_HOME", + "USERPROFILE", + "HOMEDRIVE", + "HOMEPATH", + "GIT_CONFIG_GLOBAL", + "GIT_CONFIG_SYSTEM", + } { + if v, ok := os.LookupEnv(ev); ok { + cmd.Env = append(cmd.Env, ev+"="+v) + } + } + } 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. + ) } for _, ev := range proxyEnvVars { if v, ok := os.LookupEnv(ev); ok { @@ -244,7 +273,7 @@ func (cli *GitCLI) Run(ctx context.Context, args ...string) (_ []byte, err error } func getGitSSHCommand(knownHosts string) string { - gitSSHCommand := "ssh -F /dev/null" + gitSSHCommand := "ssh -F " + os.DevNull if knownHosts != "" { gitSSHCommand += " -o UserKnownHostsFile=" + knownHosts } else { diff --git a/vendor/modules.txt b/vendor/modules.txt index 3607c7a4e61f..5d5b5cc87a68 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -646,7 +646,7 @@ github.com/mitchellh/go-wordwrap # github.com/mitchellh/hashstructure/v2 v2.0.2 ## explicit; go 1.14 github.com/mitchellh/hashstructure/v2 -# github.com/moby/buildkit v0.29.0 +# github.com/moby/buildkit v0.29.1-0.20260408185135-a243ce438aee ## explicit; go 1.25.5 github.com/moby/buildkit/api/services/control github.com/moby/buildkit/api/types From 720f91fdd4d1ee045d7a4290d1326c936acdc47c Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:41:38 +0100 Subject: [PATCH 2/3] gitutil: migrate to BuildKit GitCLI API Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- build/git.go | 14 ++- commands/history/ls.go | 5 +- tests/bake.go | 29 ++--- tests/build.go | 15 +-- tests/history.go | 5 +- tests/policy_build.go | 17 ++- util/gitutil/gittestutil/testutil.go | 30 +++-- util/gitutil/gittestutil/testutilserve.go | 6 +- util/gitutil/gitutil.go | 137 +++++++--------------- util/gitutil/gitutil_test.go | 34 ++++-- 10 files changed, 135 insertions(+), 157 deletions(-) diff --git a/build/git.go b/build/git.go index ac79b0689808..ae0a28863780 100644 --- a/build/git.go +++ b/build/git.go @@ -12,6 +12,7 @@ import ( "github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/osutil" "github.com/moby/buildkit/client" + bkgitutil "github.com/moby/buildkit/util/gitutil" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -61,7 +62,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) ( } wd = osutil.SanitizePath(wd) - gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd)) + gitc, err := gitutil.New(bkgitutil.WithDir(wd)) if err != nil { if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() { return nil, errors.Wrap(err, "git was not found in the system") @@ -69,21 +70,22 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) ( return nil, nil } - if !gitc.IsInsideWorkTree() { + if !gitc.IsInsideWorkTree(ctx) { if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() { return nil, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree") } return nil, nil } - root, err := gitc.RootDir() + root, err := gitc.WorkTree(ctx) if err != nil { return nil, errors.Wrap(err, "failed to get git root dir") } + root = osutil.SanitizePath(root) res := make(map[string]string) - if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) { + if sha, err := gitc.FullCommit(ctx); err != nil && !gitutil.IsUnknownRevision(err) { return nil, errors.Wrap(err, "failed to get git commit") } else if sha != "" { checkDirty := false @@ -92,7 +94,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) ( checkDirty = v } } - if checkDirty && gitc.IsDirty() { + if checkDirty && gitc.IsDirty(ctx) { sha += "-dirty" } if setGitLabels { @@ -103,7 +105,7 @@ func getGitAttributes(ctx context.Context, contextPath, dockerfilePath string) ( } } - if rurl, err := gitc.RemoteURL(); err == nil && rurl != "" { + if rurl, err := gitc.RemoteURL(ctx); err == nil && rurl != "" { if setGitLabels { res["label:"+ocispecs.AnnotationSource] = rurl } diff --git a/commands/history/ls.go b/commands/history/ls.go index 3e6e6f255e8a..7b834284a1a6 100644 --- a/commands/history/ls.go +++ b/commands/history/ls.go @@ -20,6 +20,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/formatter" "github.com/docker/go-units" + bkgitutil "github.com/moby/buildkit/util/gitutil" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -59,14 +60,14 @@ func runLs(ctx context.Context, dockerCli command.Cli, opts lsOptions) error { if err != nil { return err } - gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd)) + gitc, err := gitutil.New(bkgitutil.WithDir(wd)) if err != nil { if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() { return errors.Wrap(err, "git was not found in the system") } return errors.Wrapf(err, "could not find git repository for local filter") } - remote, err := gitc.RemoteURL() + remote, err := gitc.RemoteURL(ctx) if err != nil { return errors.Wrapf(err, "could not get remote URL for local filter") } diff --git a/tests/bake.go b/tests/bake.go index 4daa0515f6bc..791fc4a8aca2 100644 --- a/tests/bake.go +++ b/tests/bake.go @@ -23,6 +23,7 @@ import ( "github.com/moby/buildkit/identity" provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types" "github.com/moby/buildkit/util/contentutil" + bkgitutil "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil/integration" "github.com/pkg/errors" @@ -551,7 +552,7 @@ COPY super-cool.txt / fstest.CreateFile("bar/super-cool.txt", []byte("super cool"), 0600), ) - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar") @@ -688,7 +689,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -718,7 +719,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -765,7 +766,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + git, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -834,7 +835,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + git, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -868,14 +869,14 @@ EOT ) dirDest := t.TempDir() - gitSpec, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + gitSpec, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(gitSpec, t) gittestutil.GitAdd(gitSpec, t, "docker-bake.hcl") gittestutil.GitCommit(gitSpec, t, "initial commit") addrSpec := gittestutil.GitServeHTTP(gitSpec, t) - gitSrc, err := gitutil.New(gitutil.WithWorkingDir(dirSrc)) + gitSrc, err := gitutil.New(bkgitutil.WithDir(dirSrc)) require.NoError(t, err) gittestutil.GitInit(gitSrc, t) gittestutil.GitAdd(gitSrc, t, "foo") @@ -909,7 +910,7 @@ COPY super-cool.txt / ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) gittestutil.GitAdd(git, t, "docker-bake.hcl", "bar") @@ -948,7 +949,7 @@ COPY --from=files file.txt /file.txt ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) gittestutil.GitAdd(git, t, "docker-bake.hcl", "build", "files-src") @@ -984,7 +985,7 @@ COPY --from=files marker.txt /marker.txt ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) gittestutil.GitAdd(git, t, "docker-bake.hcl", "build", "marker.txt") @@ -1023,7 +1024,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + git, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -1071,7 +1072,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + git, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -1127,7 +1128,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + git, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -1179,7 +1180,7 @@ COPY foo /foo fstest.CreateFile("foo", []byte("foo"), 0600), ) - git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec)) + git, err := gitutil.New(bkgitutil.WithDir(dirSpec)) require.NoError(t, err) gittestutil.GitInit(git, t) diff --git a/tests/build.go b/tests/build.go index 6412d2428473..6c2d229722ad 100644 --- a/tests/build.go +++ b/tests/build.go @@ -28,6 +28,7 @@ import ( provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types" "github.com/moby/buildkit/util/appdefaults" "github.com/moby/buildkit/util/contentutil" + bkgitutil "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil/integration" "github.com/opencontainers/go-digest" @@ -130,7 +131,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -155,7 +156,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -182,7 +183,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -215,7 +216,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -248,7 +249,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -281,7 +282,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -403,7 +404,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) diff --git a/tests/history.go b/tests/history.go index 6437968cf7e4..3adabc28dde4 100644 --- a/tests/history.go +++ b/tests/history.go @@ -12,6 +12,7 @@ import ( "github.com/containerd/continuity/fs/fstest" "github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil/gittestutil" + bkgitutil "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/testutil/integration" "github.com/stretchr/testify/require" ) @@ -196,7 +197,7 @@ COPY foo /foo ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -245,7 +246,7 @@ EOT ) dirDest := t.TempDir() - git, err := gitutil.New(gitutil.WithWorkingDir(dir)) + git, err := gitutil.New(bkgitutil.WithDir(dir)) require.NoError(t, err) gittestutil.GitInit(git, t) diff --git a/tests/policy_build.go b/tests/policy_build.go index 16be87ae5b2f..35837416b84f 100644 --- a/tests/policy_build.go +++ b/tests/policy_build.go @@ -3,6 +3,7 @@ package tests import ( "archive/tar" "bytes" + "context" "encoding/json" "errors" "fmt" @@ -20,6 +21,7 @@ import ( "github.com/moby/buildkit/client" "github.com/moby/buildkit/identity" "github.com/moby/buildkit/util/contentutil" + bkgitutil "github.com/moby/buildkit/util/gitutil" "github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil/httpserver" "github.com/moby/buildkit/util/testutil/integration" @@ -822,7 +824,7 @@ func testBuildPolicyGit(t *testing.T, sb integration.Sandbox) { require.NoError(t, os.WriteFile(filepath.Join(gitDir, "Dockerfile"), []byte("FROM busybox:latest\nRUN echo git\n"), 0600)) require.NoError(t, os.WriteFile(filepath.Join(gitDir, "a"), []byte("a"), 0600)) - git, err := gitutil.New(gitutil.WithWorkingDir(gitDir)) + git, err := gitutil.New(bkgitutil.WithDir(gitDir)) require.NoError(t, err) gittestutil.GitInit(git, t) @@ -834,15 +836,18 @@ func testBuildPolicyGit(t *testing.T, sb integration.Sandbox) { require.NoError(t, os.WriteFile(filepath.Join(gitDir, "b"), []byte("b"), 0600)) gittestutil.GitAdd(git, t, "b") gittestutil.GitCommit(git, t, "b") - _, err = git.Run("checkout", "-B", "v2") + _, err = git.Run(context.TODO(), "checkout", "-B", "v2") require.NoError(t, err) - commitHead, err := git.Run("rev-parse", "HEAD") + commitHeadB, err := git.Run(context.TODO(), "rev-parse", "HEAD") require.NoError(t, err) - commitTag, err := git.Run("rev-parse", "v0.1") + commitHead := strings.TrimSpace(string(commitHeadB)) + commitTagB, err := git.Run(context.TODO(), "rev-parse", "v0.1") require.NoError(t, err) - commitTagCommit, err := git.Run("rev-parse", "v0.1^{commit}") + commitTag := strings.TrimSpace(string(commitTagB)) + commitTagCommitB, err := git.Run(context.TODO(), "rev-parse", "v0.1^{commit}") require.NoError(t, err) + commitTagCommit := strings.TrimSpace(string(commitTagCommitB)) baseURL := gittestutil.GitServeHTTP(git, t) tagURL := baseURL + "#v0.1" branchURL := baseURL + "#v2" @@ -1318,7 +1323,7 @@ default allow = true decision := {"allow": allow} `), 0600)) - git, err := gitutil.New(gitutil.WithWorkingDir(gitDir)) + git, err := gitutil.New(bkgitutil.WithDir(gitDir)) require.NoError(t, err) gittestutil.GitInit(git, t) gittestutil.GitAdd(git, t, ".") diff --git a/util/gitutil/gittestutil/testutil.go b/util/gitutil/gittestutil/testutil.go index a88c3aa6163a..aa5939fc56f9 100644 --- a/util/gitutil/gittestutil/testutil.go +++ b/util/gitutil/gittestutil/testutil.go @@ -1,15 +1,17 @@ package gittestutil import ( + "context" "os" "strings" "testing" "github.com/docker/buildx/util/gitutil" + "github.com/pkg/errors" "github.com/stretchr/testify/require" ) -func GitInit(c *gitutil.Git, tb testing.TB) { +func GitInit(c *gitutil.GitCLI, tb testing.TB) { tb.Helper() out, err := fakeGit(c, "init") require.NoError(tb, err) @@ -19,48 +21,48 @@ func GitInit(c *gitutil.Git, tb testing.TB) { _, _ = fakeGit(c, "branch", "-D", "master") } -func GitCommit(c *gitutil.Git, tb testing.TB, msg string) { +func GitCommit(c *gitutil.GitCLI, tb testing.TB, msg string) { tb.Helper() out, err := fakeGit(c, "commit", "--allow-empty", "-m", msg) require.NoError(tb, err) require.Contains(tb, out, "main", msg) } -func GitTag(c *gitutil.Git, tb testing.TB, tag string) { +func GitTag(c *gitutil.GitCLI, tb testing.TB, tag string) { tb.Helper() out, err := fakeGit(c, "tag", tag) require.NoError(tb, err) require.Empty(tb, out) } -func GitTagAnnotated(c *gitutil.Git, tb testing.TB, tag, message string) { +func GitTagAnnotated(c *gitutil.GitCLI, tb testing.TB, tag, message string) { tb.Helper() out, err := fakeGit(c, "tag", "-a", tag, "-m", message) require.NoError(tb, err) require.Empty(tb, out) } -func GitCheckoutBranch(c *gitutil.Git, tb testing.TB, name string) { +func GitCheckoutBranch(c *gitutil.GitCLI, tb testing.TB, name string) { tb.Helper() out, err := fakeGit(c, "checkout", "-b", name) require.NoError(tb, err) require.Empty(tb, out) } -func GitAdd(c *gitutil.Git, tb testing.TB, files ...string) { +func GitAdd(c *gitutil.GitCLI, tb testing.TB, files ...string) { tb.Helper() args := append([]string{"add"}, files...) _, err := fakeGit(c, args...) require.NoError(tb, err) } -func GitSetRemote(c *gitutil.Git, tb testing.TB, name string, url string) { +func GitSetRemote(c *gitutil.GitCLI, tb testing.TB, name string, url string) { tb.Helper() _, err := fakeGit(c, "remote", "add", name, url) require.NoError(tb, err) } -func GitSetMainUpstream(c *gitutil.Git, tb testing.TB, remote, target string) { +func GitSetMainUpstream(c *gitutil.GitCLI, tb testing.TB, remote, target string) { tb.Helper() _, err := fakeGit(c, "fetch", "--depth", "1", remote, target) require.NoError(tb, err) @@ -81,7 +83,7 @@ func Mktmp(tb testing.TB) string { return folder } -func fakeGit(c *gitutil.Git, args ...string) (string, error) { +func fakeGit(c *gitutil.GitCLI, args ...string) (string, error) { allArgs := []string{ "-c", "user.name=buildx", "-c", "user.email=buildx@docker.com", @@ -90,7 +92,15 @@ func fakeGit(c *gitutil.Git, args ...string) (string, error) { "-c", "log.showSignature=false", } allArgs = append(allArgs, args...) - return c.Run(allArgs...) + return clean(c.Run(context.TODO(), allArgs...)) +} + +func clean(dt []byte, err error) (string, error) { + out := strings.ReplaceAll(strings.Split(string(dt), "\n")[0], "'", "") + if err != nil { + err = errors.New(strings.TrimSuffix(err.Error(), "\n")) + } + return out, err } func IsAmbiguousArgument(err error) bool { diff --git a/util/gitutil/gittestutil/testutilserve.go b/util/gitutil/gittestutil/testutilserve.go index 0a6076ec43b7..8fde0f950f22 100644 --- a/util/gitutil/gittestutil/testutilserve.go +++ b/util/gitutil/gittestutil/testutilserve.go @@ -24,7 +24,7 @@ func WithAccessToken(token string) GitServeOpt { } } -func GitServeHTTP(c *gitutil.Git, t testing.TB, opts ...GitServeOpt) (url string) { +func GitServeHTTP(c *gitutil.GitCLI, t testing.TB, opts ...GitServeOpt) (url string) { t.Helper() gitUpdateServerInfo(c, t) ctx, cancel := context.WithCancelCause(context.TODO()) @@ -38,7 +38,7 @@ func GitServeHTTP(c *gitutil.Git, t testing.TB, opts ...GitServeOpt) (url string done := make(chan struct{}) name := "test.git" - dir, err := c.GitDir() + dir, err := c.GitDir(context.TODO()) if err != nil { cancel(err) } @@ -93,7 +93,7 @@ func GitServeHTTP(c *gitutil.Git, t testing.TB, opts ...GitServeOpt) (url string return fmt.Sprintf("http://%s/%s", addr, name) } -func gitUpdateServerInfo(c *gitutil.Git, tb testing.TB) { +func gitUpdateServerInfo(c *gitutil.GitCLI, tb testing.TB) { tb.Helper() _, err := fakeGit(c, "update-server-info") require.NoError(tb, err) diff --git a/util/gitutil/gitutil.go b/util/gitutil/gitutil.go index cca79f9001f4..97d939bf1946 100644 --- a/util/gitutil/gitutil.go +++ b/util/gitutil/gitutil.go @@ -1,122 +1,98 @@ package gitutil import ( - "bytes" "context" "net/url" - "os" - "os/exec" "path/filepath" "strings" "github.com/docker/buildx/util/osutil" + bkgitutil "github.com/moby/buildkit/util/gitutil" "github.com/pkg/errors" ) -// Git represents an active git object -type Git struct { - ctx context.Context - wd string - gitpath string +// GitCLI represents an active git object. +type GitCLI struct { + bkgitutil.GitCLI } -// Option provides a variadic option for configuring the git client. -type Option func(b *Git) +// New initializes a new git client. +func New(opts ...bkgitutil.Option) (*GitCLI, error) { + cli := bkgitutil.NewGitCLI(append(opts, bkgitutil.WithHostGitConfig())...) -// WithContext sets context. -func WithContext(ctx context.Context) Option { - return func(b *Git) { - b.ctx = ctx - } -} - -// WithWorkingDir sets working directory. -func WithWorkingDir(wd string) Option { - return func(b *Git) { - b.wd = wd - } -} - -// New initializes a new git client -func New(opts ...Option) (*Git, error) { - var err error - c := &Git{ - ctx: context.Background(), - } - - for _, opt := range opts { - opt(c) - } - - c.gitpath, err = gitPath(c.wd) + gitpath, err := gitPath(cli.Dir()) if err != nil { return nil, err } - return c, nil + cli = cli.New( + bkgitutil.WithGitBinary(gitpath), + bkgitutil.WithArgs("-c", "log.showSignature=false"), + ) + return &GitCLI{*cli}, nil } -func (c *Git) IsInsideWorkTree() bool { - out, err := c.Run("rev-parse", "--is-inside-work-tree") +func (cli *GitCLI) IsInsideWorkTree(ctx context.Context) bool { + out, err := cli.clean(cli.Run(ctx, "rev-parse", "--is-inside-work-tree")) return out == "true" && err == nil } -func (c *Git) IsDirty() bool { - out, err := c.Run("status", "--porcelain", "--ignored") - return strings.TrimSpace(out) != "" || err != nil +func (cli *GitCLI) IsDirty(ctx context.Context) bool { + out, err := cli.Run(ctx, "status", "--porcelain", "--ignored") + return strings.TrimSpace(string(out)) != "" || err != nil } -func (c *Git) RootDir() (string, error) { - root, err := c.Run("rev-parse", "--show-toplevel") +func (cli *GitCLI) WorkTree(ctx context.Context) (string, error) { + root, err := cli.GitCLI.WorkTree(ctx) if err != nil { return "", err } return osutil.SanitizePath(root), nil } -func (c *Git) GitDir() (string, error) { - dir, err := c.RootDir() +func (cli *GitCLI) GitDir(ctx context.Context) (string, error) { + dir, err := cli.WorkTree(ctx) if err != nil { return "", err } return filepath.Join(dir, ".git"), nil } -func (c *Git) RemoteURL() (string, error) { - // Try default remote based on remote tracking branch - if remote, err := c.currentRemote(); err == nil && remote != "" { - if ru, err := c.clean(c.run("remote", "get-url", remote)); err == nil && ru != "" { +func (cli *GitCLI) RemoteURL(ctx context.Context) (string, error) { + // Try default remote based on remote tracking branch. + if remote, err := cli.currentRemote(ctx); err == nil && remote != "" { + if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", remote)); err == nil && ru != "" { return stripCredentials(ru), nil } } - // Next try to get the remote URL from the origin remote first - if ru, err := c.clean(c.run("remote", "get-url", "origin")); err == nil && ru != "" { + // Next try to get the remote URL from the origin remote first. + if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "origin")); err == nil && ru != "" { return stripCredentials(ru), nil } - // If that fails, try to get the remote URL from the upstream remote - if ru, err := c.clean(c.run("remote", "get-url", "upstream")); err == nil && ru != "" { + // If that fails, try to get the remote URL from the upstream remote. + if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "upstream")); err == nil && ru != "" { return stripCredentials(ru), nil } return "", errors.New("no remote URL found for either origin or upstream") } -func (c *Git) FullCommit() (string, error) { - return c.clean(c.run("show", "--format=%H", "HEAD", "--quiet", "--")) +func (cli *GitCLI) FullCommit(ctx context.Context) (string, error) { + return cli.clean(cli.Run(ctx, "show", "--format=%H", "HEAD", "--quiet", "--")) } -func (c *Git) ShortCommit() (string, error) { - return c.clean(c.run("show", "--format=%h", "HEAD", "--quiet", "--")) +func (cli *GitCLI) ShortCommit(ctx context.Context) (string, error) { + return cli.clean(cli.Run(ctx, "show", "--format=%h", "HEAD", "--quiet", "--")) } -func (c *Git) Tag() (string, error) { +func (cli *GitCLI) Tag(ctx context.Context) (string, error) { var tag string var err error for _, fn := range []func() (string, error){ func() (string, error) { - return c.clean(c.run("tag", "--points-at", "HEAD", "--sort", "-version:creatordate")) + return cli.clean(cli.Run(ctx, "tag", "--points-at", "HEAD", "--sort", "-version:creatordate")) }, func() (string, error) { - return c.clean(c.run("describe", "--tags", "--abbrev=0")) + return cli.clean(cli.Run(ctx, "describe", "--tags", "--abbrev=0")) }, } { tag, err = fn() @@ -127,36 +103,8 @@ func (c *Git) Tag() (string, error) { return tag, err } -func (c *Git) Run(args ...string) (string, error) { - return c.clean(c.run(args...)) -} - -func (c *Git) run(args ...string) (string, error) { - var extraArgs = []string{ - "-c", "log.showSignature=false", - } - - args = append(extraArgs, args...) - cmd := exec.CommandContext(c.ctx, c.gitpath, args...) - if c.wd != "" { - cmd.Dir = c.wd - } - - // Override the locale to ensure consistent output - cmd.Env = append(os.Environ(), "LC_ALL=C") - - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - if err := cmd.Run(); err != nil { - return "", errors.New(stderr.String()) - } - return stdout.String(), nil -} - -func (c *Git) clean(out string, err error) (string, error) { +func (cli *GitCLI) clean(dt []byte, err error) (string, error) { + out := string(dt) out = strings.ReplaceAll(strings.Split(out, "\n")[0], "'", "") if err != nil { err = errors.New(strings.TrimSuffix(err.Error(), "\n")) @@ -164,16 +112,15 @@ func (c *Git) clean(out string, err error) (string, error) { return out, err } -func (c *Git) currentRemote() (string, error) { - symref, err := c.Run("symbolic-ref", "-q", "HEAD") +func (cli *GitCLI) currentRemote(ctx context.Context) (string, error) { + symref, err := cli.clean(cli.Run(ctx, "symbolic-ref", "-q", "HEAD")) if err != nil { return "", err } if symref == "" { return "", nil } - // git for-each-ref --format='%(upstream:remotename)' - remote, err := c.Run("for-each-ref", "--format=%(upstream:remotename)", symref) + remote, err := cli.clean(cli.Run(ctx, "for-each-ref", "--format=%(upstream:remotename)", symref)) if err != nil { return "", err } diff --git a/util/gitutil/gitutil_test.go b/util/gitutil/gitutil_test.go index 8a21b25ef1e7..db868c3a8b4c 100644 --- a/util/gitutil/gitutil_test.go +++ b/util/gitutil/gitutil_test.go @@ -1,6 +1,8 @@ package gitutil_test import ( + "context" + "strings" "testing" "github.com/docker/buildx/util/gitutil" @@ -9,6 +11,7 @@ import ( ) func TestGit(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) @@ -16,17 +19,18 @@ func TestGit(t *testing.T) { gittestutil.GitInit(c, t) gittestutil.GitCommit(c, t, "bar") - out, err := c.Run("status") + out, err := c.Run(ctx, "status") require.NoError(t, err) require.NotEmpty(t, out) - out, err = c.Run("not-exist") + out, err = c.Run(ctx, "not-exist") require.Error(t, err) require.Empty(t, out) - require.Equal(t, "git: 'not-exist' is not a git command. See 'git --help'.", err.Error()) + require.Contains(t, err.Error(), "git: 'not-exist' is not a git command. See 'git --help'.") } func TestGitFullCommit(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) @@ -34,12 +38,13 @@ func TestGitFullCommit(t *testing.T) { gittestutil.GitInit(c, t) gittestutil.GitCommit(c, t, "bar") - out, err := c.FullCommit() + out, err := c.FullCommit(ctx) require.NoError(t, err) require.Equal(t, 40, len(out)) } func TestGitShortCommit(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) @@ -47,38 +52,41 @@ func TestGitShortCommit(t *testing.T) { gittestutil.GitInit(c, t) gittestutil.GitCommit(c, t, "bar") - out, err := c.ShortCommit() + out, err := c.ShortCommit(ctx) require.NoError(t, err) require.Equal(t, 7, len(out)) } func TestGitFullCommitErr(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) gittestutil.GitInit(c, t) - _, err = c.FullCommit() + _, err = c.FullCommit(ctx) require.Error(t, err) require.True(t, gitutil.IsUnknownRevision(err)) require.False(t, gittestutil.IsAmbiguousArgument(err)) } func TestGitShortCommitErr(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) gittestutil.GitInit(c, t) - _, err = c.ShortCommit() + _, err = c.ShortCommit(ctx) require.Error(t, err) require.True(t, gitutil.IsUnknownRevision(err)) require.False(t, gittestutil.IsAmbiguousArgument(err)) } func TestGitTagsPointsAt(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) @@ -89,12 +97,13 @@ func TestGitTagsPointsAt(t *testing.T) { gittestutil.GitCommit(c, t, "foo") gittestutil.GitTag(c, t, "v0.9.0") - out, err := c.Run("tag", "--points-at", "HEAD", "--sort", "-version:creatordate") + out, err := c.Run(ctx, "tag", "--points-at", "HEAD", "--sort", "-version:creatordate") require.NoError(t, err) - require.Equal(t, "v0.9.0", out) + require.Equal(t, "v0.9.0", strings.TrimSpace(string(out))) } func TestGitDescribeTags(t *testing.T) { + ctx := context.TODO() gittestutil.Mktmp(t) c, err := gitutil.New() require.NoError(t, err) @@ -105,12 +114,13 @@ func TestGitDescribeTags(t *testing.T) { gittestutil.GitCommit(c, t, "foo") gittestutil.GitTag(c, t, "v0.9.0") - out, err := c.Run("describe", "--tags", "--abbrev=0") + out, err := c.Run(ctx, "describe", "--tags", "--abbrev=0") require.NoError(t, err) - require.Equal(t, "v0.9.0", out) + require.Equal(t, "v0.9.0", strings.TrimSpace(string(out))) } func TestGitRemoteURL(t *testing.T) { + ctx := context.TODO() type remote struct { name string url string @@ -218,7 +228,7 @@ func TestGitRemoteURL(t *testing.T) { } } - ru, err := c.RemoteURL() + ru, err := c.RemoteURL(ctx) if tt.fail { require.Error(t, err) return From 4f89a2407a8bbd0de11fbc05515d50e80c14a5f5 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:04:37 +0200 Subject: [PATCH 3/3] gitutil: use BuildKit urlutil.RedactCredentials for remote URLs Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- util/gitutil/credentials_test.go | 44 ------------------- util/gitutil/gitutil.go | 21 ++------- .../moby/buildkit/util/urlutil/redact.go | 33 ++++++++++++++ vendor/modules.txt | 1 + 4 files changed, 38 insertions(+), 61 deletions(-) delete mode 100644 util/gitutil/credentials_test.go create mode 100644 vendor/github.com/moby/buildkit/util/urlutil/redact.go diff --git a/util/gitutil/credentials_test.go b/util/gitutil/credentials_test.go deleted file mode 100644 index 7225f8dc1b2b..000000000000 --- a/util/gitutil/credentials_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package gitutil - -import "testing" - -func TestStripCredentials(t *testing.T) { - cases := []struct { - name string - url string - want string - }{ - { - name: "non-blank Password", - url: "https://user:password@host.tld/this:that", - want: "https://host.tld/this:that", - }, - { - name: "blank Password", - url: "https://user@host.tld/this:that", - want: "https://host.tld/this:that", - }, - { - name: "blank Username", - url: "https://:password@host.tld/this:that", - want: "https://host.tld/this:that", - }, - { - name: "blank Username, blank Password", - url: "https://host.tld/this:that", - want: "https://host.tld/this:that", - }, - { - name: "invalid URL", - url: "1https://foo.com", - want: "1https://foo.com", - }, - } - for _, tt := range cases { - t.Run(tt.name, func(t *testing.T) { - if g, w := stripCredentials(tt.url), tt.want; g != w { - t.Fatalf("got: %q\nwant: %q", g, w) - } - }) - } -} diff --git a/util/gitutil/gitutil.go b/util/gitutil/gitutil.go index 97d939bf1946..bfd3a4a01006 100644 --- a/util/gitutil/gitutil.go +++ b/util/gitutil/gitutil.go @@ -2,12 +2,12 @@ package gitutil import ( "context" - "net/url" "path/filepath" "strings" "github.com/docker/buildx/util/osutil" bkgitutil "github.com/moby/buildkit/util/gitutil" + bkurlutil "github.com/moby/buildkit/util/urlutil" "github.com/pkg/errors" ) @@ -62,16 +62,16 @@ func (cli *GitCLI) RemoteURL(ctx context.Context) (string, error) { // Try default remote based on remote tracking branch. if remote, err := cli.currentRemote(ctx); err == nil && remote != "" { if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", remote)); err == nil && ru != "" { - return stripCredentials(ru), nil + return bkurlutil.RedactCredentials(ru), nil } } // Next try to get the remote URL from the origin remote first. if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "origin")); err == nil && ru != "" { - return stripCredentials(ru), nil + return bkurlutil.RedactCredentials(ru), nil } // If that fails, try to get the remote URL from the upstream remote. if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "upstream")); err == nil && ru != "" { - return stripCredentials(ru), nil + return bkurlutil.RedactCredentials(ru), nil } return "", errors.New("no remote URL found for either origin or upstream") } @@ -135,16 +135,3 @@ func IsUnknownRevision(err error) bool { errMsg := strings.ToLower(err.Error()) return strings.Contains(errMsg, "unknown revision or path not in the working tree") || strings.Contains(errMsg, "bad revision") } - -// stripCredentials takes a URL and strips username and password from it. -// e.g. "https://user:password@host.tld/path.git" will be changed to -// "https://host.tld/path.git". -// TODO: remove this function once fix from BuildKit is vendored here -func stripCredentials(s string) string { - ru, err := url.Parse(s) - if err != nil { - return s // string is not a URL, just return it - } - ru.User = nil - return ru.String() -} diff --git a/vendor/github.com/moby/buildkit/util/urlutil/redact.go b/vendor/github.com/moby/buildkit/util/urlutil/redact.go new file mode 100644 index 000000000000..385e6aef861e --- /dev/null +++ b/vendor/github.com/moby/buildkit/util/urlutil/redact.go @@ -0,0 +1,33 @@ +package urlutil + +import ( + "net/url" +) + +const mask = "xxxxx" + +// RedactCredentials takes a URL and redacts username and password from it. +// e.g. "https://user:password@host.tld/path.git" will be changed to +// "https://xxxxx:xxxxx@host.tld/path.git". +func RedactCredentials(s string) string { + ru, err := url.Parse(s) + if err != nil { + return s // string is not a URL, just return it + } + var ( + hasUsername bool + hasPassword bool + ) + if ru.User != nil { + hasUsername = len(ru.User.Username()) > 0 + _, hasPassword = ru.User.Password() + } + if hasUsername && hasPassword { + ru.User = url.UserPassword(mask, mask) + } else if hasUsername { + ru.User = url.User(mask) + } else if hasPassword { + ru.User = url.UserPassword(ru.User.Username(), mask) + } + return ru.String() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 5d5b5cc87a68..dafa7fa817a7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -743,6 +743,7 @@ github.com/moby/buildkit/util/tracing/delegated github.com/moby/buildkit/util/tracing/detect github.com/moby/buildkit/util/tracing/env github.com/moby/buildkit/util/tracing/otlptracegrpc +github.com/moby/buildkit/util/urlutil github.com/moby/buildkit/version # github.com/moby/docker-image-spec v1.3.1 ## explicit; go 1.18