diff options
-rw-r--r-- | changelogs/unreleased/sh-export-gl-project-git-archive.yml | 5 | ||||
-rw-r--r-- | internal/command/command.go | 5 | ||||
-rw-r--r-- | internal/git/command.go | 6 | ||||
-rw-r--r-- | internal/git/safecmd.go | 10 | ||||
-rw-r--r-- | internal/git/safecmd_test.go | 32 | ||||
-rw-r--r-- | internal/gitaly/service/repository/archive.go | 8 | ||||
-rw-r--r-- | internal/gitaly/service/repository/archive_test.go | 45 | ||||
-rw-r--r-- | internal/testhelper/testhelper.go | 8 |
8 files changed, 111 insertions, 8 deletions
diff --git a/changelogs/unreleased/sh-export-gl-project-git-archive.yml b/changelogs/unreleased/sh-export-gl-project-git-archive.yml new file mode 100644 index 000000000..1b0999a7a --- /dev/null +++ b/changelogs/unreleased/sh-export-gl-project-git-archive.yml @@ -0,0 +1,5 @@ +--- +title: Export GL_REPOSITORY and GL_PROJECT_PATH in git archive call +merge_request: 2557 +author: +type: changed diff --git a/internal/command/command.go b/internal/command/command.go index 40f8844a9..5ea8ab752 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -458,3 +458,8 @@ func checkNullArgv(cmd *exec.Cmd) error { func (c *Command) Args() []string { return c.cmd.Args } + +// Env is an accessor for the environment variables +func (c *Command) Env() []string { + return c.cmd.Env +} diff --git a/internal/git/command.go b/internal/git/command.go index 866269424..6fb682913 100644 --- a/internal/git/command.go +++ b/internal/git/command.go @@ -9,13 +9,15 @@ import ( "gitlab.com/gitlab-org/gitaly/internal/git/repository" ) -// unsafeCmd creates a git.unsafeCmd with the given args and Repository -func unsafeCmd(ctx context.Context, repo repository.GitRepo, args ...string) (*command.Command, error) { +// unsafeCmdWithEnv creates a git.unsafeCmd with the given args, environment, and Repository +func unsafeCmdWithEnv(ctx context.Context, extraEnv []string, repo repository.GitRepo, args ...string) (*command.Command, error) { args, env, err := argsAndEnv(repo, args...) if err != nil { return nil, err } + env = append(env, extraEnv...) + return unsafeBareCmd(ctx, CmdStream{}, env, args...) } diff --git a/internal/git/safecmd.go b/internal/git/safecmd.go index a0a240123..c45aa3a8f 100644 --- a/internal/git/safecmd.go +++ b/internal/git/safecmd.go @@ -213,15 +213,21 @@ func ConvertGlobalOptions(options *gitalypb.GlobalOptions) []Option { return globals } -// SafeCmd creates a git.Command with the given args and Repository. It +// SafeCmd creates a command.Command with the given args and Repository. It // validates the arguments in the command before executing. func SafeCmd(ctx context.Context, repo repository.GitRepo, globals []Option, sc Cmd) (*command.Command, error) { + return SafeCmdWithEnv(ctx, nil, repo, globals, sc) +} + +// SafeCmdWithEnv creates a command.Command with the given args, environment, and Repository. It +// validates the arguments in the command before executing. +func SafeCmdWithEnv(ctx context.Context, env []string, repo repository.GitRepo, globals []Option, sc Cmd) (*command.Command, error) { args, err := combineArgs(globals, sc) if err != nil { return nil, err } - return unsafeCmd(ctx, repo, args...) + return unsafeCmdWithEnv(ctx, env, repo, args...) } // SafeBareCmd creates a git.Command with the given args, stream, and env. It diff --git a/internal/git/safecmd_test.go b/internal/git/safecmd_test.go index 0829d9a58..6ab199390 100644 --- a/internal/git/safecmd_test.go +++ b/internal/git/safecmd_test.go @@ -200,6 +200,11 @@ func TestSafeCmdValid(t *testing.T) { // ignore first 3 indeterministic args (executable path and repo args) require.Equal(t, tt.expectArgs, cmd.Args()[3:]) + cmd, err = git.SafeCmdWithEnv(ctx, nil, testRepo, tt.globals, tt.subCmd) + require.NoError(t, err) + // ignore first 3 indeterministic args (executable path and repo args) + require.Equal(t, tt.expectArgs, cmd.Args()[3:]) + cmd, err = git.SafeStdinCmd(ctx, testRepo, tt.globals, tt.subCmd) require.NoError(t, err) require.Equal(t, tt.expectArgs, cmd.Args()[3:]) @@ -215,6 +220,33 @@ func TestSafeCmdValid(t *testing.T) { } } +func TestSafeCmdWithEnv(t *testing.T) { + testRepo, _, cleanup := testhelper.NewTestRepo(t) + defer cleanup() + + ctx, cancel := testhelper.Context() + defer cancel() + + reenableGitCmd := disableGitCmd() + defer reenableGitCmd() + + globals := []git.Option{ + git.Flag{Name: "--aaaa-bbbb"}, + } + + subCmd := git.SubCmd{Name: "cccc"} + endOfOptions := "--end-of-options" + expectArgs := []string{"--aaaa-bbbb", "cccc", endOfOptions} + + env := []string{"TEST_VAR1=1", "TEST_VAR2=2"} + + cmd, err := git.SafeCmdWithEnv(ctx, env, testRepo, globals, subCmd) + require.NoError(t, err) + // ignore first 3 indeterministic args (executable path and repo args) + require.Equal(t, expectArgs, cmd.Args()[3:]) + require.Subset(t, cmd.Env(), env) +} + func disableGitCmd() testhelper.Cleanup { oldBinPath := config.Config.Git.BinPath config.Config.Git.BinPath = "/bin/echo" diff --git a/internal/gitaly/service/repository/archive.go b/internal/gitaly/service/repository/archive.go index e60950678..807f97ebd 100644 --- a/internal/gitaly/service/repository/archive.go +++ b/internal/gitaly/service/repository/archive.go @@ -2,6 +2,7 @@ package repository import ( "context" + "fmt" "io" "os" "os/exec" @@ -150,7 +151,12 @@ func handleArchive(ctx context.Context, writer io.Writer, in *gitalypb.GetArchiv pathspecs = append(pathspecs, ":(exclude)"+exclude) } - archiveCommand, err := git.SafeCmd(ctx, in.GetRepository(), nil, git.SubCmd{ + env := []string{ + fmt.Sprintf("GL_REPOSITORY=%s", in.GetRepository().GetGlRepository()), + fmt.Sprintf("GL_PROJECT_PATH=%s", in.GetRepository().GetGlProjectPath()), + } + + archiveCommand, err := git.SafeCmdWithEnv(ctx, env, in.GetRepository(), nil, git.SubCmd{ Name: "archive", Flags: []git.Option{git.ValueFlag{"--format", format}, git.ValueFlag{"--prefix", in.GetPrefix() + "/"}}, Args: args, diff --git a/internal/gitaly/service/repository/archive_test.go b/internal/gitaly/service/repository/archive_test.go index ffbc8540c..4f600d836 100644 --- a/internal/gitaly/service/repository/archive_test.go +++ b/internal/gitaly/service/repository/archive_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "gitlab.com/gitlab-org/gitaly/streamio" @@ -369,6 +370,50 @@ func TestGetArchivePathInjection(t *testing.T) { require.Zero(t, authorizedKeysFileStat.Size()) } +func TestGetArchiveEnv(t *testing.T) { + serverSocketPath, stop := runRepoServer(t) + defer stop() + + client, conn := newRepositoryClient(t, serverSocketPath) + defer conn.Close() + + testRepo, _, cleanupFn := testhelper.NewTestRepo(t) + defer cleanupFn() + + commitID := "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863" + + ctx, cancel := testhelper.Context() + defer cancel() + + req := &gitalypb.GetArchiveRequest{ + Repository: testRepo, + CommitId: commitID, + } + + tmpFile, err := ioutil.TempFile("", "archive.sh") + require.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + err = tmpFile.Chmod(0755) + require.NoError(t, err) + + tmpFile.Write([]byte(`#!/bin/sh +env | grep ^GL_`)) + tmpFile.Close() + + oldBinPath := config.Config.Git.BinPath + config.Config.Git.BinPath = tmpFile.Name() + defer func() { config.Config.Git.BinPath = oldBinPath }() + + stream, err := client.GetArchive(ctx, req) + require.NoError(t, err) + + data, err := consumeArchive(stream) + require.NoError(t, err) + require.Contains(t, string(data), "GL_REPOSITORY="+testhelper.GlRepository) + require.Contains(t, string(data), "GL_PROJECT_PATH="+testhelper.GlProjectPath) +} + func compressedFileContents(t *testing.T, format gitalypb.GetArchiveRequest_Format, name string) []byte { switch format { case gitalypb.GetArchiveRequest_TAR: diff --git a/internal/testhelper/testhelper.go b/internal/testhelper/testhelper.go index 5c8be0bcb..134367ead 100644 --- a/internal/testhelper/testhelper.go +++ b/internal/testhelper/testhelper.go @@ -56,6 +56,7 @@ const ( testGitEnv = "testdata/git-env" GlRepository = "project-1" GlID = "user-123" + GlProjectPath = "gitlab-org/gitlab-test" ) var configureOnce sync.Once @@ -500,9 +501,10 @@ func Context(opts ...ContextOpt) (context.Context, func()) { func CreateRepo(t testing.TB, storagePath, relativePath string) *gitalypb.Repository { require.NoError(t, os.MkdirAll(filepath.Dir(storagePath), 0755), "making repo parent dir") return &gitalypb.Repository{ - StorageName: "default", - RelativePath: relativePath, - GlRepository: GlRepository, + StorageName: "default", + RelativePath: relativePath, + GlRepository: GlRepository, + GlProjectPath: GlProjectPath, } } |