Skip to content

Commit 9906874

Browse files
recreate git config during update to prevent config alteration
1 parent 268c11c commit 9906874

File tree

2 files changed

+173
-12
lines changed

2 files changed

+173
-12
lines changed

get_git.go

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (g *GitGetter) Get(dst string, u *url.URL) error {
125125
return err
126126
}
127127
if err == nil {
128-
err = g.update(ctx, dst, sshKeyFile, ref, depth)
128+
err = g.update(ctx, dst, sshKeyFile, u, ref, depth)
129129
} else {
130130
err = g.clone(ctx, dst, sshKeyFile, u, ref, depth)
131131
}
@@ -228,21 +228,48 @@ func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.UR
228228
return nil
229229
}
230230

231-
func (g *GitGetter) update(ctx context.Context, dst, sshKeyFile, ref string, depth int) error {
232-
// Determine if we're a branch. If we're NOT a branch, then we just
233-
// switch to master prior to checking out
234-
cmd := exec.CommandContext(ctx, "git", "show-ref", "-q", "--verify", "refs/heads/"+ref)
231+
func (g *GitGetter) update(ctx context.Context, dst, sshKeyFile string, u *url.URL, ref string, depth int) error {
232+
// Remove all variations of .git directories
233+
err := removeCaseInsensitiveGitDirectory(dst)
234+
if err != nil {
235+
return err
236+
}
237+
238+
// Initialize the git repository
239+
cmd := exec.CommandContext(ctx, "git", "init")
235240
cmd.Dir = dst
241+
err = getRunCommand(cmd)
242+
if err != nil {
243+
return err
244+
}
236245

237-
if getRunCommand(cmd) != nil {
238-
// Not a branch, switch to default branch. This will also catch
239-
// non-existent branches, in which case we want to switch to default
240-
// and then checkout the proper branch later.
241-
ref = findDefaultBranch(ctx, dst)
246+
// Add the git remote
247+
cmd = exec.CommandContext(ctx, "git", "remote", "add", "origin", "--", u.String())
248+
cmd.Dir = dst
249+
err = getRunCommand(cmd)
250+
if err != nil {
251+
return err
242252
}
243253

244-
// We have to be on a branch to pull
245-
if err := g.checkout(ctx, dst, ref); err != nil {
254+
// Fetch the remote ref
255+
cmd = exec.CommandContext(ctx, "git", "fetch", "origin", "--", ref)
256+
cmd.Dir = dst
257+
err = getRunCommand(cmd)
258+
if err != nil {
259+
return err
260+
}
261+
262+
// Reset the branch to the fetched ref
263+
cmd = exec.CommandContext(ctx, "git", "reset", "--hard", "FETCH_HEAD")
264+
cmd.Dir = dst
265+
err = getRunCommand(cmd)
266+
if err != nil {
267+
return err
268+
}
269+
270+
// Checkout ref branch
271+
err = g.checkout(ctx, dst, ref)
272+
if err != nil {
246273
return err
247274
}
248275

@@ -377,3 +404,20 @@ func checkGitVersion(ctx context.Context, min string) error {
377404

378405
return nil
379406
}
407+
408+
// removeCaseInsensitiveGitDirectory removes all .git directory variations
409+
func removeCaseInsensitiveGitDirectory(dst string) error {
410+
files, err := os.ReadDir(dst)
411+
if err != nil {
412+
return fmt.Errorf("Failed to read the destination directory %s during git update", dst)
413+
}
414+
for _, f := range files {
415+
if strings.EqualFold(f.Name(), ".git") && f.IsDir() {
416+
err := os.RemoveAll(filepath.Join(dst, f.Name()))
417+
if err != nil {
418+
return fmt.Errorf("Failed to remove the .git directory in the destination directory %s during git update", dst)
419+
}
420+
}
421+
}
422+
return nil
423+
}

get_git_test.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,123 @@ func TestGitGetter_BadRemoteUrl(t *testing.T) {
866866
}
867867
}
868868

869+
func TestGitGetter_BadGitConfig(t *testing.T) {
870+
if !testHasGit {
871+
t.Log("git not found, skipping")
872+
t.Skip()
873+
}
874+
875+
ctx := context.Background()
876+
g := new(GitGetter)
877+
dst := tempDir(t)
878+
879+
url, err := url.Parse("https://github.com/hashicorp/go-getter")
880+
if err != nil {
881+
t.Fatal(err)
882+
}
883+
884+
_, err = os.Stat(dst)
885+
if err != nil && !os.IsNotExist(err) {
886+
t.Fatalf(err.Error())
887+
}
888+
if err == nil {
889+
// Update the repository containing the bad git config.
890+
// This should remove the bad git config file and initialize a new one.
891+
err = g.update(ctx, dst, testGitToken, url, "main", 1)
892+
} else {
893+
// Clone a repository with a git config file
894+
err = g.clone(ctx, dst, testGitToken, url, "main", 1)
895+
if err != nil {
896+
t.Fatalf(err.Error())
897+
}
898+
899+
// Edit the git config file to simulate a bad git config
900+
gitConfigPath := filepath.Join(dst, ".git", "config")
901+
err = os.WriteFile(gitConfigPath, []byte("bad config"), 0600)
902+
if err != nil {
903+
t.Fatalf(err.Error())
904+
}
905+
906+
// Update the repository containing the bad git config.
907+
// This should remove the bad git config file and initialize a new one.
908+
err = g.update(ctx, dst, testGitToken, url, "main", 1)
909+
}
910+
if err != nil {
911+
t.Fatalf(err.Error())
912+
}
913+
914+
// Check if the .git/config file contains "bad config"
915+
gitConfigPath := filepath.Join(dst, ".git", "config")
916+
configBytes, err := os.ReadFile(gitConfigPath)
917+
if err != nil {
918+
t.Fatalf(err.Error())
919+
}
920+
if strings.Contains(string(configBytes), "bad config") {
921+
t.Fatalf("The .git/config file contains 'bad config'")
922+
}
923+
}
924+
925+
func TestGitGetter_BadGitDirName(t *testing.T) {
926+
if !testHasGit {
927+
t.Log("git not found, skipping")
928+
t.Skip()
929+
}
930+
931+
ctx := context.Background()
932+
g := new(GitGetter)
933+
dst := tempDir(t)
934+
935+
url, err := url.Parse("https://github.com/hashicorp/go-getter")
936+
if err != nil {
937+
t.Fatal(err)
938+
}
939+
940+
_, err = os.Stat(dst)
941+
if err != nil && !os.IsNotExist(err) {
942+
t.Fatalf(err.Error())
943+
}
944+
if err == nil {
945+
// Remove all variations of .git directories
946+
err = removeCaseInsensitiveGitDirectory(dst)
947+
if err != nil {
948+
t.Fatalf(err.Error())
949+
}
950+
} else {
951+
// Clone a repository with a git directory
952+
err = g.clone(ctx, dst, testGitToken, url, "main", 1)
953+
if err != nil {
954+
t.Fatalf(err.Error())
955+
}
956+
957+
// Rename the .git directory to .GIT
958+
oldPath := filepath.Join(dst, ".git")
959+
newPath := filepath.Join(dst, ".GIT")
960+
err = os.Rename(oldPath, newPath)
961+
if err != nil {
962+
t.Fatalf(err.Error())
963+
}
964+
965+
// Remove all variations of .git directories
966+
err = removeCaseInsensitiveGitDirectory(dst)
967+
if err != nil {
968+
t.Fatalf(err.Error())
969+
}
970+
}
971+
if err != nil {
972+
t.Fatalf(err.Error())
973+
}
974+
975+
// Check if the .GIT directory exists
976+
if _, err := os.Stat(filepath.Join(dst, ".GIT")); !os.IsNotExist(err) {
977+
t.Fatalf(".GIT directory still exists")
978+
}
979+
980+
// Check if the .git directory exists
981+
if _, err := os.Stat(filepath.Join(dst, ".git")); !os.IsNotExist(err) {
982+
t.Fatalf(".git directory still exists")
983+
}
984+
}
985+
869986
// gitRepo is a helper struct which controls a single temp git repo.
870987
type gitRepo struct {
871988
t *testing.T

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy