Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2020-09-14 09:02:44 +0300
committerStan Hu <stanhu@gmail.com>2020-09-15 18:50:55 +0300
commit3cef6ba80866e1c5367d86d8f29fb1e87eb96a08 (patch)
treec9ac7c350c6da25c559208694af427dee353a634
parent4805333598f9ed608652cfd28650cabf110fc646 (diff)
Export GL_REPOSITORY and GL_PROJECT_PATH in `git archive` call
To support bundling Git LFS objects within a `git archive` call, we will need a custom LFS smudge filter that will download the LFS data. To do this, we will need to make an API call request to check the the requested LFS object ID actually belongs to the LFS object network, so we need to export `GL_REPOSITORY` to the environment. `GL_PROJECT_PATH` may be useful for debugging purposes.
-rw-r--r--changelogs/unreleased/sh-export-gl-project-git-archive.yml5
-rw-r--r--internal/command/command.go5
-rw-r--r--internal/git/command.go6
-rw-r--r--internal/git/safecmd.go10
-rw-r--r--internal/git/safecmd_test.go32
-rw-r--r--internal/gitaly/service/repository/archive.go8
-rw-r--r--internal/gitaly/service/repository/archive_test.go45
-rw-r--r--internal/testhelper/testhelper.go8
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 fd0b23387..971963aa0 100644
--- a/internal/testhelper/testhelper.go
+++ b/internal/testhelper/testhelper.go
@@ -57,6 +57,7 @@ const (
testGitEnv = "testdata/git-env"
GlRepository = "project-1"
GlID = "user-123"
+ GlProjectPath = "gitlab-org/gitlab-test"
)
var configureOnce sync.Once
@@ -501,9 +502,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,
}
}