mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 23:08:26 +00:00
Co-authored-by: Rui Chen <rui@chenrui.dev>
This commit is contained in:
@@ -4,11 +4,12 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
pegomock "github.com/petergtz/pegomock/v4"
|
||||
models "github.com/runatlantis/atlantis/server/events/models"
|
||||
logging "github.com/runatlantis/atlantis/server/logging"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MockWorkingDir struct {
|
||||
|
||||
@@ -71,7 +71,7 @@ type GithubAppCredentials struct {
|
||||
Key []byte
|
||||
Hostname string
|
||||
apiURL *url.URL
|
||||
installationID int64
|
||||
InstallationID int64
|
||||
tr *ghinstallation.Transport
|
||||
AppSlug string
|
||||
}
|
||||
@@ -122,8 +122,8 @@ func (c *GithubAppCredentials) GetToken() (string, error) {
|
||||
}
|
||||
|
||||
func (c *GithubAppCredentials) getInstallationID() (int64, error) {
|
||||
if c.installationID != 0 {
|
||||
return c.installationID, nil
|
||||
if c.InstallationID != 0 {
|
||||
return c.InstallationID, nil
|
||||
}
|
||||
|
||||
tr := http.DefaultTransport
|
||||
@@ -148,8 +148,8 @@ func (c *GithubAppCredentials) getInstallationID() (int64, error) {
|
||||
return 0, fmt.Errorf("wrong number of installations, expected 1, found %d", len(installations))
|
||||
}
|
||||
|
||||
c.installationID = installations[0].GetID()
|
||||
return c.installationID, nil
|
||||
c.InstallationID = installations[0].GetID()
|
||||
return c.InstallationID, nil
|
||||
}
|
||||
|
||||
func (c *GithubAppCredentials) transport() (*ghinstallation.Transport, error) {
|
||||
|
||||
@@ -69,3 +69,40 @@ func TestGithubClient_AppAuthentication(t *testing.T) {
|
||||
t.Errorf("app token was not cached: %q != %q", token, newToken)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGithubClient_MultipleAppAuthentication(t *testing.T) {
|
||||
logger := logging.NewNoopLogger(t)
|
||||
defer disableSSLVerification()()
|
||||
testServer, err := testdata.GithubMultipleAppTestServer(t)
|
||||
Ok(t, err)
|
||||
|
||||
anonCreds := &vcs.GithubAnonymousCredentials{}
|
||||
anonClient, err := vcs.NewGithubClient(testServer, anonCreds, vcs.GithubConfig{}, logging.NewNoopLogger(t))
|
||||
Ok(t, err)
|
||||
tempSecrets, err := anonClient.ExchangeCode(logger, "good-code")
|
||||
Ok(t, err)
|
||||
|
||||
appCreds := &vcs.GithubAppCredentials{
|
||||
AppID: tempSecrets.ID,
|
||||
InstallationID: 1,
|
||||
Key: []byte(testdata.GithubPrivateKey),
|
||||
Hostname: testServer,
|
||||
}
|
||||
_, err = vcs.NewGithubClient(testServer, appCreds, vcs.GithubConfig{}, logging.NewNoopLogger(t))
|
||||
Ok(t, err)
|
||||
|
||||
token, err := appCreds.GetToken()
|
||||
Ok(t, err)
|
||||
|
||||
newToken, err := appCreds.GetToken()
|
||||
Ok(t, err)
|
||||
|
||||
user, err := appCreds.GetUser()
|
||||
Ok(t, err)
|
||||
|
||||
Assert(t, user == "", "user should be empty")
|
||||
|
||||
if token != newToken {
|
||||
t.Errorf("app token was not cached: %q != %q", token, newToken)
|
||||
}
|
||||
}
|
||||
|
||||
128
server/events/vcs/testdata/fixtures.go
vendored
128
server/events/vcs/testdata/fixtures.go
vendored
@@ -496,6 +496,79 @@ var githubAppInstallationJSON = `[
|
||||
}
|
||||
]`
|
||||
|
||||
var githubAppMultipleInstallationJSON = `[
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"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": "some-token",
|
||||
@@ -741,3 +814,58 @@ func GithubAppTestServer(t *testing.T) (string, error) {
|
||||
|
||||
return testServerURL.Host, err
|
||||
}
|
||||
|
||||
func GithubMultipleAppTestServer(t *testing.T) (string, error) {
|
||||
counter := 0
|
||||
testServer := httptest.NewTLSServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.RequestURI {
|
||||
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")) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(githubAppMultipleInstallationJSON)) // nolint: errcheck
|
||||
return
|
||||
case "/api/v3/apps/some-app":
|
||||
token := strings.Replace(r.Header.Get("Authorization"), "token ", "", 1)
|
||||
|
||||
// token is taken from githubAppTokenJSON
|
||||
if token != "some-token" {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("Invalid installation token")) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
w.Write([]byte(githubAppJSON)) // nolint: errcheck
|
||||
return
|
||||
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")) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
appToken := fmt.Sprintf(githubAppTokenJSON, counter)
|
||||
counter++
|
||||
w.Write([]byte(appToken)) // nolint: errcheck
|
||||
return
|
||||
default:
|
||||
t.Errorf("got unexpected request at %q", r.RequestURI)
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
}))
|
||||
|
||||
testServerURL, err := url.Parse(testServer.URL)
|
||||
|
||||
return testServerURL.Host, err
|
||||
}
|
||||
|
||||
@@ -239,18 +239,20 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
githubCredentials = &vcs.GithubAppCredentials{
|
||||
AppID: userConfig.GithubAppID,
|
||||
Key: privateKey,
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
AppID: userConfig.GithubAppID,
|
||||
InstallationID: userConfig.GithubInstallationID,
|
||||
Key: privateKey,
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
}
|
||||
githubAppEnabled = true
|
||||
} else if userConfig.GithubAppID != 0 && userConfig.GithubAppKey != "" {
|
||||
githubCredentials = &vcs.GithubAppCredentials{
|
||||
AppID: userConfig.GithubAppID,
|
||||
Key: []byte(userConfig.GithubAppKey),
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
AppID: userConfig.GithubAppID,
|
||||
InstallationID: userConfig.GithubInstallationID,
|
||||
Key: []byte(userConfig.GithubAppKey),
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
}
|
||||
githubAppEnabled = true
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ type UserConfig struct {
|
||||
GithubAppKey string `mapstructure:"gh-app-key"`
|
||||
GithubAppKeyFile string `mapstructure:"gh-app-key-file"`
|
||||
GithubAppSlug string `mapstructure:"gh-app-slug"`
|
||||
GithubInstallationID int64 `mapstructure:"gh-installation-id"`
|
||||
GithubTeamAllowlist string `mapstructure:"gh-team-allowlist"`
|
||||
GiteaBaseURL string `mapstructure:"gitea-base-url"`
|
||||
GiteaToken string `mapstructure:"gitea-token"`
|
||||
|
||||
Reference in New Issue
Block a user