Skip to content

Commit

Permalink
Test against a live repo, fix accordingly
Browse files Browse the repository at this point in the history
  • Loading branch information
unRob committed Apr 21, 2020
1 parent f522034 commit d95405a
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 104 deletions.
35 changes: 35 additions & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,20 @@ func TestExecute_ValidateVCSConfig(t *testing.T) {
},
true,
},
{
"just github app set",
map[string]interface{}{
GHAppIDFlag: "1",
},
true,
},
{
"just github app key set",
map[string]interface{}{
GHAppKeyFlag: "key.pem",
},
true,
},
{
"just gitlab user set",
map[string]interface{}{
Expand Down Expand Up @@ -448,6 +462,14 @@ func TestExecute_ValidateVCSConfig(t *testing.T) {
},
false,
},
{
"github app and key set and should be successful",
map[string]interface{}{
GHAppIDFlag: "1",
GHAppKeyFlag: "key.pem",
},
false,
},
{
"gitlab user and gitlab token set and should be successful",
map[string]interface{}{
Expand Down Expand Up @@ -546,6 +568,19 @@ func TestExecute_GithubUser(t *testing.T) {
Equals(t, "user", passedConfig.GithubUser)
}

func TestExecute_GithubApp(t *testing.T) {
t.Log("Should remove the @ from the github username if it's passed.")
c := setup(map[string]interface{}{
GHAppKeyFlag: "key.pem",
GHAppIDFlag: "1",
RepoWhitelistFlag: "*",
})
err := c.Execute()
Ok(t, err)

Equals(t, int64(1), passedConfig.GithubAppID)
}

func TestExecute_GitlabUser(t *testing.T) {
t.Log("Should remove the @ from the gitlab username if it's passed.")
c := setup(map[string]interface{}{
Expand Down
4 changes: 2 additions & 2 deletions server/events/git_cred_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// 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 {
func WriteGitCreds(gitUser string, gitToken string, gitHostname string, home string, logger *logging.SimpleLogger, ignoreExisting bool) error {
const credsFilename = ".git-credentials"
credsFile := filepath.Join(home, credsFilename)
credsFileContents := `https://%s:%s@%s`
Expand All @@ -24,7 +24,7 @@ func WriteGitCreds(gitUser string, gitToken string, gitHostname string, home str
// 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 {
if _, err := os.Stat(credsFile); err == nil && !ignoreExisting {
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)
Expand Down
14 changes: 7 additions & 7 deletions server/events/git_cred_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestWriteGitCreds_WriteFile(t *testing.T) {
tmp, cleanup := TempDir(t)
defer cleanup()

err := events.WriteGitCreds("user", "token", "hostname", tmp, logger)
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)

expContents := `https://user:token@hostname`
Expand All @@ -39,7 +39,7 @@ func TestWriteGitCreds_WillNotOverwrite(t *testing.T) {
err := ioutil.WriteFile(credsFile, []byte("contents"), 0600)
Ok(t, err)

actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger)
actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
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)
}
Expand All @@ -56,7 +56,7 @@ func TestWriteGitCreds_NoErrIfContentsSame(t *testing.T) {
err := ioutil.WriteFile(credsFile, []byte(contents), 0600)
Ok(t, err)

err = events.WriteGitCreds("user", "token", "hostname", tmp, logger)
err = events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)
}

Expand All @@ -71,15 +71,15 @@ func TestWriteGitCreds_ErrIfCannotRead(t *testing.T) {
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)
actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
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)
actErr := events.WriteGitCreds("user", "token", "hostname", "/this/dir/does/not/exist", logger, false)
ErrEquals(t, expErr, actErr)
}

Expand All @@ -88,7 +88,7 @@ func TestWriteGitCreds_ConfigureGitCredentialHelper(t *testing.T) {
tmp, cleanup := TempDir(t)
defer cleanup()

err := events.WriteGitCreds("user", "token", "hostname", tmp, logger)
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)

expOutput := `store`
Expand All @@ -102,7 +102,7 @@ func TestWriteGitCreds_ConfigureGitUrlOverride(t *testing.T) {
tmp, cleanup := TempDir(t)
defer cleanup()

err := events.WriteGitCreds("user", "token", "hostname", tmp, logger)
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)

expOutput := `ssh://git@hostname`
Expand Down
99 changes: 47 additions & 52 deletions server/events/vcs/fixtures/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,49 +292,45 @@ var githubConversionJSON = `{
"pem": "%s"
}`

var githubAppInfoJSON = `{
"id": 1,
"slug": "atlantis",
"node_id": "MDExOkludGVncmF0aW9uMQ==",
"owner": {
"login": "github",
"id": 1,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
"url": "https://api.github.com/orgs/github",
"repos_url": "https://api.github.com/orgs/github/repos",
"events_url": "https://api.github.com/orgs/github/events",
"hooks_url": "https://api.github.com/orgs/github/hooks",
"issues_url": "https://api.github.com/orgs/github/issues",
"members_url": "https://api.github.com/orgs/github/members{/member}",
"public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"description": "A great organization"
},
"name": "Atlantis",
"description": "atlantis",
"external_url": "https://atlantis.example.com",
"html_url": "https://github.com/apps/atlantis",
"created_at": "2017-07-08T16:18:44-04:00",
"updated_at": "2017-07-08T16:18:44-04:00",
"permissions":{
"checks": "write",
"contents": "write",
"issues": "write",
"pull_requests": "write",
"repository_hooks": "write",
"statuses": "write"
},
"events": [
"check_run",
"create",
"delete",
"pull_request",
"push",
"issues"
],
"installations_count": 1
}`
var githubAppInstallationJSON = `[
{
"id": 1,
"account": {
"login": "github",
"id": 1,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
"url": "https://api.github.com/orgs/github",
"repos_url": "https://api.github.com/orgs/github/repos",
"events_url": "https://api.github.com/orgs/github/events",
"hooks_url": "https://api.github.com/orgs/github/hooks",
"issues_url": "https://api.github.com/orgs/github/issues",
"members_url": "https://api.github.com/orgs/github/members{/member}",
"public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"description": "A great organization"
},
"access_tokens_url": "https://api.github.com/installations/1/access_tokens",
"repositories_url": "https://api.github.com/installation/repositories",
"html_url": "https://github.com/organizations/github/settings/installations/1",
"app_id": 1,
"target_id": 1,
"target_type": "Organization",
"permissions": {
"metadata": "read",
"contents": "read",
"issues": "write",
"single_file": "write"
},
"events": [
"push",
"pull_request"
],
"single_file_name": "config.yml",
"repository_selection": "selected"
}
]`

// nolint: gosec
var githubAppTokenJSON = `{
"token": "v1.1f699f1069f60xx%d",
"expires_at": "2050-01-01T00:00:00Z",
Expand Down Expand Up @@ -488,27 +484,26 @@ func GithubAppTestServer(t *testing.T) (string, error) {
testServer := httptest.NewTLSServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
// https://developer.github.com/v3/apps/#get-the-authenticated-github-app
case "/api/v3/app":
case "/api/v3/app-manifests/good-code/conversions":
encodedKey := strings.Join(strings.Split(GithubPrivateKey, "\n"), "\\n")
appInfo := fmt.Sprintf(githubConversionJSON, encodedKey)
w.Write([]byte(appInfo)) // nolint: errcheck
// https://developer.github.com/v3/apps/#list-installations
case "/api/v3/app/installations":
token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1)
if err := validateGithubToken(token); err != nil {
w.WriteHeader(403)
w.Write([]byte("Invalid token"))
w.Write([]byte("Invalid token")) // nolint: errcheck
return
}

w.Write([]byte(githubAppInfoJSON)) // nolint: errcheck
w.Write([]byte(githubAppInstallationJSON)) // nolint: errcheck
return
case "/api/v3/app-manifests/good-code/conversions":
encodedKey := strings.Join(strings.Split(GithubPrivateKey, "\n"), "\\n")
appInfo := fmt.Sprintf(githubConversionJSON, encodedKey)
w.Write([]byte(appInfo)) // nolint: errcheck
case "/api/v3/app/installations/1/access_tokens":
case "/api/v3//app/installations/1/access_tokens":
token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1)
if err := validateGithubToken(token); err != nil {
w.WriteHeader(403)
w.Write([]byte("Invalid token"))
w.Write([]byte("Invalid token")) // nolint: errcheck
return
}

Expand Down
54 changes: 20 additions & 34 deletions server/events/vcs/github_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package vcs

import (
"context"
"log"
"fmt"
"net/http"
"net/url"
"strings"

"github.com/bradleyfalzon/ghinstallation"
"github.com/google/go-github/v30/github"
"github.com/pkg/errors"
)

// GithubCredentials handles creating http.Clients that authenticate
Expand Down Expand Up @@ -69,7 +70,7 @@ type GithubAppCredentials struct {
Hostname string
apiURL *url.URL
installationID int64
token *github.InstallationToken
tr *ghinstallation.Transport
}

// Client returns a github app installation client
Expand All @@ -88,38 +89,12 @@ func (c *GithubAppCredentials) GetUser() string {

// GetToken returns a fresh installation token
func (c *GithubAppCredentials) GetToken() (string, error) {
if c.token != nil {
log.Println(c.token.GetExpiresAt())
return c.token.GetToken(), nil
}

transport, err := c.Client()
if err != nil {
return "", err
}

apiURL := c.getAPIURL()
var client *github.Client

if apiURL.Hostname() == "github.com" {
client = github.NewClient(transport)
} else {
client, _ = github.NewEnterpriseClient(apiURL.String(), apiURL.String(), transport)
}

installationID, err := c.getInstallationID()
tr, err := c.transport()
if err != nil {
return "", err
return "", errors.Wrap(err, "transport failed")
}

token, _, err := client.Apps.CreateInstallationToken(context.Background(), installationID, &github.InstallationTokenOptions{})

if err != nil {
return "", err
}

c.token = token
return token.GetToken(), nil
return tr.Token(context.Background())
}

func (c *GithubAppCredentials) getInstallationID() (int64, error) {
Expand All @@ -139,16 +114,25 @@ func (c *GithubAppCredentials) getInstallationID() (int64, error) {
client := github.NewClient(&http.Client{Transport: t})
client.BaseURL = c.getAPIURL()
ctx := context.Background()
app, _, err := client.Apps.Get(ctx, "")

installations, _, err := client.Apps.ListInstallations(ctx, nil)
if err != nil {
return 0, err
}

c.installationID = app.GetID()
if len(installations) != 1 {
return 0, fmt.Errorf("wrong number of installations, expected 1, found %d", len(installations))
}

c.installationID = installations[0].GetID()
return c.installationID, nil
}

func (c *GithubAppCredentials) transport() (*ghinstallation.Transport, error) {
if c.tr != nil {
return c.tr, nil
}

installationID, err := c.getInstallationID()
if err != nil {
return nil, err
Expand All @@ -157,7 +141,9 @@ func (c *GithubAppCredentials) transport() (*ghinstallation.Transport, error) {
tr := http.DefaultTransport
itr, err := ghinstallation.NewKeyFromFile(tr, c.AppID, installationID, c.KeyPath)
if err == nil {
itr.BaseURL = c.getAPIURL().String()
apiURL := c.getAPIURL()
itr.BaseURL = strings.TrimSuffix(apiURL.String(), "/")
c.tr = itr
}
return itr, err
}
Expand Down
2 changes: 1 addition & 1 deletion server/events/vcs/github_credentials_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ func TestGithubClient_AppAuthentication(t *testing.T) {
Ok(t, err)

if token != newToken {
t.Errorf("app token was not cached")
t.Errorf("app token was not cached: %q != %q", token, newToken)
}
}
Loading

0 comments on commit d95405a

Please sign in to comment.