From 1886073554e4a88934f5d36683a19ecfd1dbc8e4 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt <psteinhardt@gitlab.com> Date: Thu, 24 Nov 2022 08:27:28 +0100 Subject: [PATCH] hook: Replace broken ad-hoc implementation to get envvars In the `hook` package we have an ad-hoc implementation to retrieve an environment variable's value from an array. This implementation has two problems: - It retrieves the first value instead of the last value as would be done by `os.Getenv()` in case the environment variable is defined multiple times. - It can segfault in case the environment variable doesn't have an equals sign in it. Fix both bugs by instead using `env.ExtractValue()`. Changelog: fixed --- internal/gitaly/hook/custom.go | 7 ++++--- internal/gitaly/hook/postreceive.go | 11 ----------- internal/gitaly/hook/prereceive.go | 7 ++++--- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/internal/gitaly/hook/custom.go b/internal/gitaly/hook/custom.go index 9db59adaeb..4fb8d34cda 100644 --- a/internal/gitaly/hook/custom.go +++ b/internal/gitaly/hook/custom.go @@ -11,6 +11,7 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/command" "gitlab.com/gitlab-org/gitaly/v15/internal/git" + "gitlab.com/gitlab-org/gitaly/v15/internal/helper/env" "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb" "golang.org/x/sys/unix" ) @@ -150,7 +151,7 @@ func (m *GitLabHookManager) customHooksEnv(ctx context.Context, payload git.Hook customEnvs := append(command.AllowedEnvironment(envs), pushOptionsEnv(pushOptions)...) - objectDirectory := getEnvVar("GIT_OBJECT_DIRECTORY", envs) + objectDirectory := env.ExtractValue(envs, "GIT_OBJECT_DIRECTORY") if objectDirectory == "" && payload.Repo.GetGitObjectDirectory() != "" { objectDirectory = filepath.Join(repoPath, payload.Repo.GetGitObjectDirectory()) } @@ -158,7 +159,7 @@ func (m *GitLabHookManager) customHooksEnv(ctx context.Context, payload git.Hook customEnvs = append(customEnvs, "GIT_OBJECT_DIRECTORY="+objectDirectory) } - alternateObjectDirectories := getEnvVar("GIT_ALTERNATE_OBJECT_DIRECTORIES", envs) + alternateObjectDirectories := env.ExtractValue(envs, "GIT_ALTERNATE_OBJECT_DIRECTORIES") if alternateObjectDirectories == "" && len(payload.Repo.GetGitAlternateObjectDirectories()) != 0 { var absolutePaths []string for _, alternateObjectDirectory := range payload.Repo.GetGitAlternateObjectDirectories() { @@ -176,7 +177,7 @@ func (m *GitLabHookManager) customHooksEnv(ctx context.Context, payload git.Hook // By default, we should take PATH from the given set of environment variables, if // it's contained in there. Otherwise, we need to take the current process's PATH // environment, which would also be the default injected by the command package. - currentPath := getEnvVar("PATH", envs) + currentPath := env.ExtractValue(envs, "PATH") if currentPath == "" { currentPath = os.Getenv("PATH") } diff --git a/internal/gitaly/hook/postreceive.go b/internal/gitaly/hook/postreceive.go index cc4394c859..a597204830 100644 --- a/internal/gitaly/hook/postreceive.go +++ b/internal/gitaly/hook/postreceive.go @@ -31,17 +31,6 @@ const ( maxMessageTextWidth = maxMessageWidth - 2*terminalMessagePadding ) -func getEnvVar(key string, vars []string) string { - for _, varPair := range vars { - kv := strings.SplitN(varPair, "=", 2) - if kv[0] == key { - return kv[1] - } - } - - return "" -} - func printMessages(messages []gitlab.PostReceiveMessage, w io.Writer) error { for _, message := range messages { if _, err := w.Write([]byte("\n")); err != nil { diff --git a/internal/gitaly/hook/prereceive.go b/internal/gitaly/hook/prereceive.go index 544800ff0d..ad9e034a52 100644 --- a/internal/gitaly/hook/prereceive.go +++ b/internal/gitaly/hook/prereceive.go @@ -13,6 +13,7 @@ import ( "gitlab.com/gitlab-org/gitaly/v15/internal/git" "gitlab.com/gitlab-org/gitaly/v15/internal/gitlab" "gitlab.com/gitlab-org/gitaly/v15/internal/helper" + "gitlab.com/gitlab-org/gitaly/v15/internal/helper/env" "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb" ) @@ -90,13 +91,13 @@ func (m *GitLabHookManager) PreReceiveHook(ctx context.Context, repo *gitalypb.R return nil } -func (m *GitLabHookManager) preReceiveHook(ctx context.Context, payload git.HooksPayload, repo *gitalypb.Repository, pushOptions, env []string, changes []byte, stdout, stderr io.Writer) error { +func (m *GitLabHookManager) preReceiveHook(ctx context.Context, payload git.HooksPayload, repo *gitalypb.Repository, pushOptions, envs []string, changes []byte, stdout, stderr io.Writer) error { repoPath, err := m.locator.GetRepoPath(repo) if err != nil { return helper.ErrInternalf("getting repo path: %v", err) } - if gitObjDir, gitAltObjDirs := getEnvVar("GIT_OBJECT_DIRECTORY", env), getEnvVar("GIT_ALTERNATE_OBJECT_DIRECTORIES", env); gitObjDir != "" && gitAltObjDirs != "" { + if gitObjDir, gitAltObjDirs := env.ExtractValue(envs, "GIT_OBJECT_DIRECTORY"), env.ExtractValue(envs, "GIT_ALTERNATE_OBJECT_DIRECTORIES"); gitObjDir != "" && gitAltObjDirs != "" { gitObjectDirRel, gitAltObjectDirRel, err := getRelativeObjectDirs(repoPath, gitObjDir, gitAltObjDirs) if err != nil { return helper.ErrInternalf("getting relative git object directories: %v", err) @@ -165,7 +166,7 @@ func (m *GitLabHookManager) preReceiveHook(ctx context.Context, payload git.Hook return fmt.Errorf("creating custom hooks executor: %w", err) } - customEnv, err := m.customHooksEnv(ctx, payload, pushOptions, env) + customEnv, err := m.customHooksEnv(ctx, payload, pushOptions, envs) if err != nil { return helper.ErrInternalf("constructing custom hook environment: %v", err) } -- GitLab