-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #711 from ImperialXT/master
Create .git-credentials to allow secure auth when cloning private repos
- Loading branch information
Showing
7 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package events | ||
|
||
import ( | ||
"fmt" | ||
"github.com/pkg/errors" | ||
"github.com/runatlantis/atlantis/server/logging" | ||
"io/ioutil" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
// WriteGitCreds generates a .git-credentials file containing the username and token | ||
// used for authenticating with git over HTTPS | ||
// It will create the file in home/.git-credentials | ||
func WriteGitCreds(gitUser string, gitToken string, gitHostname string, home string, logger *logging.SimpleLogger) error { | ||
const credsFilename = ".git-credentials" | ||
credsFile := filepath.Join(home, credsFilename) | ||
credsFileContents := `https://%s:%s@%s` | ||
config := fmt.Sprintf(credsFileContents, gitUser, gitToken, gitHostname) | ||
|
||
// If there is already a .git-credentials file and its contents aren't exactly | ||
// what we would have written to it, then we error out because we don't | ||
// want to overwrite anything | ||
if _, err := os.Stat(credsFile); err == nil { | ||
currContents, err := ioutil.ReadFile(credsFile) // nolint: gosec | ||
if err != nil { | ||
return errors.Wrapf(err, "trying to read %s to ensure we're not overwriting it", credsFile) | ||
} | ||
if config != string(currContents) { | ||
return fmt.Errorf("can't write git-credentials to %s because that file has contents that would be overwritten", credsFile) | ||
} | ||
// Otherwise we don't need to write the file because it already has | ||
// what we need. | ||
return nil | ||
} | ||
|
||
if err := ioutil.WriteFile(credsFile, []byte(config), 0600); err != nil { | ||
return errors.Wrapf(err, "writing generated %s file with user, token and hostname to %s", credsFilename, credsFile) | ||
} | ||
|
||
logger.Info("wrote git credentials to %s", credsFile) | ||
|
||
cmd := exec.Command("git", "config", "--global", "credential.helper", "store") | ||
if out, err := cmd.CombinedOutput(); err != nil { | ||
return errors.Wrapf(err, "There was an error running %s: %s", strings.Join(cmd.Args, " "), string(out)) | ||
} | ||
logger.Info("successfully ran %s", strings.Join(cmd.Args, " ")) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package events_test | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/runatlantis/atlantis/server/events" | ||
"github.com/runatlantis/atlantis/server/logging" | ||
. "github.com/runatlantis/atlantis/testing" | ||
) | ||
|
||
var logger *logging.SimpleLogger | ||
|
||
// Test that we write the file as expected | ||
func TestWriteGitCreds_WriteFile(t *testing.T) { | ||
tmp, cleanup := TempDir(t) | ||
defer cleanup() | ||
|
||
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger) | ||
Ok(t, err) | ||
|
||
expContents := `https://user:token@hostname` | ||
|
||
actContents, err := ioutil.ReadFile(filepath.Join(tmp, ".git-credentials")) | ||
Ok(t, err) | ||
Equals(t, expContents, string(actContents)) | ||
} | ||
|
||
// Test that if the file already exists and its contents will be modified if | ||
// we write our config that we error out | ||
func TestWriteGitCreds_WillNotOverwrite(t *testing.T) { | ||
tmp, cleanup := TempDir(t) | ||
defer cleanup() | ||
|
||
credsFile := filepath.Join(tmp, ".git-credentials") | ||
err := ioutil.WriteFile(credsFile, []byte("contents"), 0600) | ||
Ok(t, err) | ||
|
||
actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger) | ||
expErr := fmt.Sprintf("can't write git-credentials to %s because that file has contents that would be overwritten", tmp+"/.git-credentials") | ||
ErrEquals(t, expErr, actErr) | ||
} | ||
|
||
// Test that if the file already exists and its contents will NOT be modified if | ||
// we write our config that we don't error. | ||
func TestWriteGitCreds_NoErrIfContentsSame(t *testing.T) { | ||
tmp, cleanup := TempDir(t) | ||
defer cleanup() | ||
|
||
credsFile := filepath.Join(tmp, ".git-credentials") | ||
contents := `https://user:token@hostname` | ||
|
||
err := ioutil.WriteFile(credsFile, []byte(contents), 0600) | ||
Ok(t, err) | ||
|
||
err = events.WriteGitCreds("user", "token", "hostname", tmp, logger) | ||
Ok(t, err) | ||
} | ||
|
||
// Test that if we can't read the existing file to see if the contents will be | ||
// the same that we just error out. | ||
func TestWriteGitCreds_ErrIfCannotRead(t *testing.T) { | ||
tmp, cleanup := TempDir(t) | ||
defer cleanup() | ||
|
||
credsFile := filepath.Join(tmp, ".git-credentials") | ||
err := ioutil.WriteFile(credsFile, []byte("can't see me!"), 0000) | ||
Ok(t, err) | ||
|
||
expErr := fmt.Sprintf("trying to read %s to ensure we're not overwriting it: open %s: permission denied", credsFile, credsFile) | ||
actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger) | ||
ErrEquals(t, expErr, actErr) | ||
} | ||
|
||
// Test that if we can't write, we error out. | ||
func TestWriteGitCreds_ErrIfCannotWrite(t *testing.T) { | ||
credsFile := "/this/dir/does/not/exist/.git-credentials" | ||
expErr := fmt.Sprintf("writing generated .git-credentials file with user, token and hostname to %s: open %s: no such file or directory", credsFile, credsFile) | ||
actErr := events.WriteGitCreds("user", "token", "hostname", "/this/dir/does/not/exist", logger) | ||
ErrEquals(t, expErr, actErr) | ||
} | ||
|
||
// Test that git is actually configured to use the credentials | ||
func TestWriteGitCreds_ConfigureGit(t *testing.T) { | ||
tmp, cleanup := TempDir(t) | ||
defer cleanup() | ||
|
||
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger) | ||
Ok(t, err) | ||
|
||
expOutput := `store` | ||
actOutput, err := exec.Command("git", "config", "--global", "credential.helper").Output() | ||
Ok(t, err) | ||
Equals(t, expOutput+"\n", string(actOutput)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters