feat: Rotate Github App Token outside of Atlantis commands (#3208)

Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Co-authored-by: PePe Amengual <jose.amengual@gmail.com>
This commit is contained in:
Jonathan Wiemers
2023-03-23 01:49:23 +01:00
committed by GitHub
parent 11a3b0018f
commit 8b90c8b0da
18 changed files with 375 additions and 60 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@ atlantis
atlantis.env
*.act
package-lock.json
Dockerfile.local
# gitreleaser
dist/

View File

@@ -7,9 +7,11 @@ services:
- 4040:4040
environment:
# https://dashboard.ngrok.com/get-started/your-authtoken
NGROK_AUTH: REPLACE-WITH-YOUR-TOKEN
# NGROK_AUTH: REPLACE-WITH-YOUR-TOKEN // set this in atlantis.env
NGROK_PROTOCOL: http
NGROK_PORT: atlantis:4141
env_file:
- ./atlantis.env
depends_on:
- atlantis
redis:

View File

@@ -19,6 +19,7 @@ import (
)
func TestApplyCommandRunner_IsLocked(t *testing.T) {
logger := logging.NewNoopLogger(t)
RegisterMockTestingT(t)
cases := []struct {
@@ -78,6 +79,7 @@ func TestApplyCommandRunner_IsLocked(t *testing.T) {
}
func TestApplyCommandRunner_IsSilenced(t *testing.T) {
logger := logging.NewNoopLogger(t)
RegisterMockTestingT(t)
cases := []struct {

View File

@@ -15,6 +15,7 @@ import (
)
func TestApproveCommandRunner_IsOwner(t *testing.T) {
logger := logging.NewNoopLogger(t)
RegisterMockTestingT(t)
cases := []struct {

View File

@@ -113,7 +113,7 @@ func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.Mock
githubGetter = mocks.NewMockGithubPullGetter()
gitlabGetter = mocks.NewMockGitlabMergeRequestGetter()
azuredevopsGetter = mocks.NewMockAzureDevopsPullGetter()
logger = logging.NewNoopLogger(t)
logger := logging.NewNoopLogger(t)
projectCommandRunner = mocks.NewMockProjectCommandRunner()
workingDir = mocks.NewMockWorkingDir()
pendingPlanFinder = mocks.NewMockPendingPlanFinder()

View File

@@ -1,16 +1,15 @@
package events
import (
"fmt"
"strings"
"github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs"
"github.com/runatlantis/atlantis/server/logging"
)
const redactedReplacement = "://:<redacted>@"
// GithubAppWorkingDir implements WorkingDir.
// It acts as a proxy to an instance of WorkingDir that refreshes the app's token
// before every clone, given Github App tokens expire quickly
@@ -22,34 +21,20 @@ type GithubAppWorkingDir struct {
// Clone writes a fresh token for Github App authentication
func (g *GithubAppWorkingDir) Clone(log logging.SimpleLogging, headRepo models.Repo, p models.PullRequest, workspace string) (string, bool, error) {
log.Info("Refreshing git tokens for Github App")
token, err := g.Credentials.GetToken()
if err != nil {
return "", false, errors.Wrap(err, "getting github token")
}
home, err := homedir.Dir()
if err != nil {
return "", false, errors.Wrap(err, "getting home dir to write ~/.git-credentials file")
}
// https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#http-based-git-access-by-an-installation
if err := WriteGitCreds("x-access-token", token, g.GithubHostname, home, log, true); err != nil {
return "", false, err
}
baseRepo := &p.BaseRepo
// Realistically, this is a super brittle way of supporting clones using gh app installation tokens
// This URL should be built during Repo creation and the struct should be immutable going forward.
// Doing this requires a larger refactor however, and can probably be coupled with supporting > 1 installation
authURL := fmt.Sprintf("://x-access-token:%s", token)
baseRepo.CloneURL = strings.Replace(baseRepo.CloneURL, "://:", authURL, 1)
baseRepo.SanitizedCloneURL = strings.Replace(baseRepo.SanitizedCloneURL, "://:", "://x-access-token:", 1)
headRepo.CloneURL = strings.Replace(headRepo.CloneURL, "://:", authURL, 1)
headRepo.SanitizedCloneURL = strings.Replace(baseRepo.SanitizedCloneURL, "://:", "://x-access-token:", 1)
// This removes the credential part from the url and leaves us with the raw http url
// git will then pick up credentials from the credential store which is set in vcs.WriteGitCreds.
// Git credentials will then be rotated by vcs.GitCredsTokenRotator
replacement := "://"
baseRepo.CloneURL = strings.Replace(baseRepo.CloneURL, "://:@", replacement, 1)
baseRepo.SanitizedCloneURL = strings.Replace(baseRepo.SanitizedCloneURL, redactedReplacement, replacement, 1)
headRepo.CloneURL = strings.Replace(headRepo.CloneURL, "://:@", replacement, 1)
headRepo.SanitizedCloneURL = strings.Replace(baseRepo.SanitizedCloneURL, redactedReplacement, replacement, 1)
return g.WorkingDir.Clone(log, headRepo, p, workspace)
}

View File

@@ -5,6 +5,7 @@ import (
"testing"
. "github.com/petergtz/pegomock"
pegomock "github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/events"
eventMocks "github.com/runatlantis/atlantis/server/events/mocks"
"github.com/runatlantis/atlantis/server/events/models"
@@ -57,6 +58,8 @@ func TestClone_GithubAppNoneExisting(t *testing.T) {
}
func TestClone_GithubAppSetsCorrectUrl(t *testing.T) {
pegomock.RegisterMockTestingT(t)
workingDir := eventMocks.NewMockWorkingDir()
credentials := vcsMocks.NewMockGithubCredentials()
@@ -82,8 +85,9 @@ func TestClone_GithubAppSetsCorrectUrl(t *testing.T) {
headRepo := baseRepo
modifiedBaseRepo := baseRepo
modifiedBaseRepo.CloneURL = "https://x-access-token:token@github.com/runatlantis/atlantis.git"
modifiedBaseRepo.SanitizedCloneURL = "https://x-access-token:<redacted>@github.com/runatlantis/atlantis.git"
// remove credentials from both urls since we want to use the credential store
modifiedBaseRepo.CloneURL = "https://github.com/runatlantis/atlantis.git"
modifiedBaseRepo.SanitizedCloneURL = "https://github.com/runatlantis/atlantis.git"
When(credentials.GetToken()).ThenReturn("token", nil)
When(workingDir.Clone(logger, modifiedBaseRepo, models.PullRequest{BaseRepo: modifiedBaseRepo}, "default")).ThenReturn(
@@ -92,5 +96,7 @@ func TestClone_GithubAppSetsCorrectUrl(t *testing.T) {
_, success, _ := ghAppWorkingDir.Clone(logger, headRepo, models.PullRequest{BaseRepo: baseRepo}, "default")
workingDir.VerifyWasCalledOnce().Clone(logger, modifiedBaseRepo, models.PullRequest{BaseRepo: modifiedBaseRepo}, "default")
Assert(t, success == true, "clone url mutation error")
}

View File

@@ -14,6 +14,7 @@ import (
)
func TestImportCommandRunner_Run(t *testing.T) {
logger := logging.NewNoopLogger(t)
RegisterMockTestingT(t)
tests := []struct {

View File

@@ -16,6 +16,7 @@ import (
)
func TestPlanCommandRunner_IsSilenced(t *testing.T) {
logger := logging.NewNoopLogger(t)
RegisterMockTestingT(t)
cases := []struct {

View File

@@ -20,6 +20,7 @@ import (
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/core/db"
"github.com/runatlantis/atlantis/server/jobs"
"github.com/runatlantis/atlantis/server/logging"
"github.com/stretchr/testify/assert"
bolt "go.etcd.io/bbolt"
@@ -187,6 +188,7 @@ func TestCleanUpPullComments(t *testing.T) {
}
func TestCleanUpLogStreaming(t *testing.T) {
logger := logging.NewNoopLogger(t)
RegisterMockTestingT(t)
t.Run("Should Clean Up Log Streaming Resources When PR is closed", func(t *testing.T) {

View File

@@ -0,0 +1,71 @@
package vcs
import (
"time"
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/logging"
"github.com/runatlantis/atlantis/server/scheduled"
)
// GitCredsTokenRotator continuously tries to rotate the github app access token every 30 seconds and writes the ~/.git-credentials file
type GitCredsTokenRotator interface {
Run()
GenerateJob() (scheduled.JobDefinition, error)
}
type githubAppTokenRotator struct {
log logging.SimpleLogging
githubCredentials GithubCredentials
githubHostname string
homeDirPath string
}
func NewGithubAppTokenRotator(
log logging.SimpleLogging,
githubCredentials GithubCredentials,
githubHostname string,
homeDirPath string) GitCredsTokenRotator {
return &githubAppTokenRotator{
log: log,
githubCredentials: githubCredentials,
githubHostname: githubHostname,
homeDirPath: homeDirPath,
}
}
// make sure interface is implemented correctly
var _ GitCredsTokenRotator = (*githubAppTokenRotator)(nil)
func (r *githubAppTokenRotator) GenerateJob() (scheduled.JobDefinition, error) {
return scheduled.JobDefinition{
Job: r,
Period: 30 * time.Second,
}, r.rotate()
}
func (r *githubAppTokenRotator) Run() {
err := r.rotate()
if err != nil {
// at least log the error message here, as we want to notify the that user that the key rotation wasn't successful
r.log.Err(err.Error())
}
}
func (r *githubAppTokenRotator) rotate() error {
r.log.Debug("Refreshing git tokens for Github App")
token, err := r.githubCredentials.GetToken()
if err != nil {
return errors.Wrap(err, "Getting github token")
}
r.log.Debug("token %s", token)
// https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#http-based-git-access-by-an-installation
if err := WriteGitCreds("x-access-token", token, r.githubHostname, r.homeDirPath, r.log, true); err != nil {
return errors.Wrap(err, "Writing ~/.git-credentials file")
}
return nil
}

View File

@@ -0,0 +1,84 @@
package vcs_test
import (
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/runatlantis/atlantis/server/events/vcs"
"github.com/runatlantis/atlantis/server/events/vcs/testdata"
"github.com/runatlantis/atlantis/server/logging"
. "github.com/runatlantis/atlantis/testing"
)
func Test_githubAppTokenRotator_GenerateJob(t *testing.T) {
defer disableSSLVerification()()
testServer, err := testdata.GithubAppTestServer(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("good-code")
Ok(t, err)
type fields struct {
githubCredentials vcs.GithubCredentials
}
tests := []struct {
name string
fields fields
credsFileWritten bool
wantErr bool
}{
{
name: "Should write .git-credentials file on start",
fields: fields{&vcs.GithubAppCredentials{
AppID: tempSecrets.ID,
Key: []byte(testdata.GithubPrivateKey),
Hostname: testServer,
}},
credsFileWritten: true,
wantErr: false,
},
{
name: "Should return an error if pem data is missing or wrong",
fields: fields{&vcs.GithubAppCredentials{
AppID: tempSecrets.ID,
Key: []byte("some bad formatted pem key"),
Hostname: testServer,
}},
credsFileWritten: false,
wantErr: true,
},
{
name: "Should return an error if app id is missing or wrong",
fields: fields{&vcs.GithubAppCredentials{
AppID: 3819,
Key: []byte(testdata.GithubPrivateKey),
Hostname: testServer,
}},
credsFileWritten: false,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpDir := t.TempDir()
r := vcs.NewGithubAppTokenRotator(logging.NewNoopLogger(t), tt.fields.githubCredentials, testServer, tmpDir)
got, err := r.GenerateJob()
if (err != nil) != tt.wantErr {
t.Errorf("githubAppTokenRotator.GenerateJob() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.credsFileWritten {
credsFileContent := fmt.Sprintf(`https://x-access-token:some-token@%s`, testServer)
actContents, err := os.ReadFile(filepath.Join(tmpDir, ".git-credentials"))
Ok(t, err)
Equals(t, credsFileContent, string(actContents))
}
Equals(t, 30*time.Second, got.Period)
})
}
}

View File

@@ -1,4 +1,4 @@
package events
package vcs
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package events_test
package vcs_test
import (
"fmt"
@@ -7,18 +7,17 @@ import (
"path/filepath"
"testing"
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/vcs"
"github.com/runatlantis/atlantis/server/logging"
. "github.com/runatlantis/atlantis/testing"
)
var logger logging.SimpleLogging
// Test that we write the file as expected
func TestWriteGitCreds_WriteFile(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
err := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)
expContents := `https://user:token@hostname`
@@ -31,13 +30,14 @@ func TestWriteGitCreds_WriteFile(t *testing.T) {
// Test that if the file already exists and it doesn't have the line we would
// have written, we write it.
func TestWriteGitCreds_Appends(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
credsFile := filepath.Join(tmp, ".git-credentials")
err := os.WriteFile(credsFile, []byte("contents"), 0600)
Ok(t, err)
err = events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
err = vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)
expContents := "contents\nhttps://user:token@hostname"
@@ -49,6 +49,7 @@ func TestWriteGitCreds_Appends(t *testing.T) {
// Test that if the file already exists and it already has the line expected
// we do nothing.
func TestWriteGitCreds_NoModification(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
credsFile := filepath.Join(tmp, ".git-credentials")
@@ -56,7 +57,7 @@ func TestWriteGitCreds_NoModification(t *testing.T) {
err := os.WriteFile(credsFile, []byte(contents), 0600)
Ok(t, err)
err = events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
err = vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)
actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials"))
Ok(t, err)
@@ -65,6 +66,7 @@ func TestWriteGitCreds_NoModification(t *testing.T) {
// Test that the github app credentials get replaced.
func TestWriteGitCreds_ReplaceApp(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
credsFile := filepath.Join(tmp, ".git-credentials")
@@ -72,7 +74,7 @@ func TestWriteGitCreds_ReplaceApp(t *testing.T) {
err := os.WriteFile(credsFile, []byte(contents), 0600)
Ok(t, err)
err = events.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true)
err = vcs.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true)
Ok(t, err)
expContets := "line1\nhttps://x-access-token:token@github.com\nline2"
actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials"))
@@ -82,6 +84,7 @@ func TestWriteGitCreds_ReplaceApp(t *testing.T) {
// Test that the github app credentials get updated when cred file is empty.
func TestWriteGitCreds_AppendApp(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
credsFile := filepath.Join(tmp, ".git-credentials")
@@ -89,7 +92,7 @@ func TestWriteGitCreds_AppendApp(t *testing.T) {
err := os.WriteFile(credsFile, []byte(contents), 0600)
Ok(t, err)
err = events.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true)
err = vcs.WriteGitCreds("x-access-token", "token", "github.com", tmp, logger, true)
Ok(t, err)
expContets := "https://x-access-token:token@github.com"
actContents, err := os.ReadFile(filepath.Join(tmp, ".git-credentials"))
@@ -100,6 +103,7 @@ func TestWriteGitCreds_AppendApp(t *testing.T) {
// 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) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
credsFile := filepath.Join(tmp, ".git-credentials")
@@ -107,23 +111,25 @@ func TestWriteGitCreds_ErrIfCannotRead(t *testing.T) {
Ok(t, err)
expErr := fmt.Sprintf("open %s: permission denied", credsFile)
actErr := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
actErr := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
ErrContains(t, expErr, actErr)
}
// Test that if we can't write, we error out.
func TestWriteGitCreds_ErrIfCannotWrite(t *testing.T) {
logger := logging.NewNoopLogger(t)
credsFile := "/this/dir/does/not/exist/.git-credentials" // nolint: gosec
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, false)
actErr := vcs.WriteGitCreds("user", "token", "hostname", "/this/dir/does/not/exist", logger, false)
ErrEquals(t, expErr, actErr)
}
// Test that git is actually configured to use the credentials
func TestWriteGitCreds_ConfigureGitCredentialHelper(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
err := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)
expOutput := `store`
@@ -134,9 +140,10 @@ func TestWriteGitCreds_ConfigureGitCredentialHelper(t *testing.T) {
// Test that git is configured to use https instead of ssh
func TestWriteGitCreds_ConfigureGitUrlOverride(t *testing.T) {
logger := logging.NewNoopLogger(t)
tmp := t.TempDir()
err := events.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
err := vcs.WriteGitCreds("user", "token", "hostname", tmp, logger, false)
Ok(t, err)
expOutput := `ssh://git@hostname`

View File

@@ -16,7 +16,7 @@ type ExecutorService struct {
log logging.SimpleLogging
// jobs
runtimeStatsPublisher JobDefinition
jobs []JobDefinition
}
func NewExecutorService(
@@ -33,11 +33,15 @@ func NewExecutorService(
}
return &ExecutorService{
log: log,
runtimeStatsPublisher: runtimeStatsPublisherJob,
log: log,
jobs: []JobDefinition{runtimeStatsPublisherJob},
}
}
func (s *ExecutorService) AddJob(jd JobDefinition) {
s.jobs = append(s.jobs, jd)
}
type JobDefinition struct {
Job Job
Period time.Duration
@@ -50,7 +54,9 @@ func (s *ExecutorService) Run() {
var wg sync.WaitGroup
s.runScheduledJob(ctx, &wg, s.runtimeStatsPublisher)
for _, jd := range s.jobs {
s.runScheduledJob(ctx, &wg, jd)
}
interrupt := make(chan os.Signal, 1)
@@ -96,6 +102,7 @@ func (s *ExecutorService) runScheduledJob(ctx context.Context, wg *sync.WaitGrou
}
//go:generate pegomock generate -m --package mocks -o mocks/mock_executor_service_job.go Job
type Job interface {
Run()
}

View File

@@ -0,0 +1,48 @@
package scheduled
import (
"testing"
"time"
"github.com/petergtz/pegomock"
"github.com/runatlantis/atlantis/server/logging"
"github.com/runatlantis/atlantis/server/scheduled/mocks"
)
func TestExecutorService_Run(t *testing.T) {
pegomock.RegisterMockTestingT(t)
mockJob := mocks.NewMockJob()
type fields struct {
log logging.SimpleLogging
jobs []JobDefinition
}
tests := []struct {
name string
fields fields
}{
{
name: "test",
fields: fields{
log: logging.NewNoopLogger(t),
jobs: []JobDefinition{
{
Job: mockJob,
Period: 1 * time.Second,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &ExecutorService{
log: tt.fields.log,
jobs: make([]JobDefinition, 0),
}
s.AddJob(tt.fields.jobs[0])
go s.Run()
time.Sleep(1050 * time.Millisecond)
mockJob.VerifyWasCalledOnce().Run()
})
}
}

View File

@@ -0,0 +1,87 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/runatlantis/atlantis/server/scheduled (interfaces: Job)
package mocks
import (
pegomock "github.com/petergtz/pegomock"
"reflect"
"time"
)
type MockJob struct {
fail func(message string, callerSkip ...int)
}
func NewMockJob(options ...pegomock.Option) *MockJob {
mock := &MockJob{}
for _, option := range options {
option.Apply(mock)
}
return mock
}
func (mock *MockJob) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockJob) FailHandler() pegomock.FailHandler { return mock.fail }
func (mock *MockJob) Run() {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockJob().")
}
params := []pegomock.Param{}
pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{})
}
func (mock *MockJob) VerifyWasCalledOnce() *VerifierMockJob {
return &VerifierMockJob{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockJob) VerifyWasCalled(invocationCountMatcher pegomock.InvocationCountMatcher) *VerifierMockJob {
return &VerifierMockJob{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockJob) VerifyWasCalledInOrder(invocationCountMatcher pegomock.InvocationCountMatcher, inOrderContext *pegomock.InOrderContext) *VerifierMockJob {
return &VerifierMockJob{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockJob) VerifyWasCalledEventually(invocationCountMatcher pegomock.InvocationCountMatcher, timeout time.Duration) *VerifierMockJob {
return &VerifierMockJob{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierMockJob struct {
mock *MockJob
invocationCountMatcher pegomock.InvocationCountMatcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierMockJob) Run() *MockJob_Run_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", params, verifier.timeout)
return &MockJob_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MockJob_Run_OngoingVerification struct {
mock *MockJob
methodInvocations []pegomock.MethodInvocation
}
func (c *MockJob_Run_OngoingVerification) GetCapturedArguments() {
}
func (c *MockJob_Run_OngoingVerification) GetAllCapturedArguments() {
}

View File

@@ -298,18 +298,19 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
}
}
home, err := homedir.Dir()
if err != nil {
return nil, errors.Wrap(err, "getting home dir to write ~/.git-credentials file")
}
if userConfig.WriteGitCreds {
home, err := homedir.Dir()
if err != nil {
return nil, errors.Wrap(err, "getting home dir to write ~/.git-credentials file")
}
if userConfig.GithubUser != "" {
if err := events.WriteGitCreds(userConfig.GithubUser, userConfig.GithubToken, userConfig.GithubHostname, home, logger, false); err != nil {
if err := vcs.WriteGitCreds(userConfig.GithubUser, userConfig.GithubToken, userConfig.GithubHostname, home, logger, false); err != nil {
return nil, err
}
}
if userConfig.GitlabUser != "" {
if err := events.WriteGitCreds(userConfig.GitlabUser, userConfig.GitlabToken, userConfig.GitlabHostname, home, logger, false); err != nil {
if err := vcs.WriteGitCreds(userConfig.GitlabUser, userConfig.GitlabToken, userConfig.GitlabHostname, home, logger, false); err != nil {
return nil, err
}
}
@@ -320,12 +321,12 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
if bitbucketBaseURL == "https://api.bitbucket.org" {
bitbucketBaseURL = "bitbucket.org"
}
if err := events.WriteGitCreds(userConfig.BitbucketUser, userConfig.BitbucketToken, bitbucketBaseURL, home, logger, false); err != nil {
if err := vcs.WriteGitCreds(userConfig.BitbucketUser, userConfig.BitbucketToken, bitbucketBaseURL, home, logger, false); err != nil {
return nil, err
}
}
if userConfig.AzureDevopsUser != "" {
if err := events.WriteGitCreds(userConfig.AzureDevopsUser, userConfig.AzureDevopsToken, "dev.azure.com", home, logger, false); err != nil {
if err := vcs.WriteGitCreds(userConfig.AzureDevopsUser, userConfig.AzureDevopsToken, "dev.azure.com", home, logger, false); err != nil {
return nil, err
}
}
@@ -461,6 +462,12 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
CheckoutDepth: userConfig.CheckoutDepth,
GithubAppEnabled: githubAppEnabled,
}
scheduledExecutorService := scheduled.NewExecutorService(
statsScope,
logger,
)
// provide fresh tokens before clone from the GitHub Apps integration, proxy workingDir
if githubAppEnabled {
if !userConfig.WriteGitCreds {
@@ -471,6 +478,13 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
Credentials: githubCredentials,
GithubHostname: userConfig.GithubHostname,
}
githubAppTokenRotator := vcs.NewGithubAppTokenRotator(logger, githubCredentials, userConfig.GithubHostname, home)
tokenJd, err := githubAppTokenRotator.GenerateJob()
if err != nil {
return nil, errors.Wrap(err, "could not write credentials")
}
scheduledExecutorService.AddJob(tokenJd)
}
projectLocker := &events.DefaultProjectLocker{
@@ -861,10 +875,6 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
GithubHostname: userConfig.GithubHostname,
GithubOrg: userConfig.GithubOrg,
}
scheduledExecutorService := scheduled.NewExecutorService(
statsScope,
logger,
)
return &Server{
AtlantisVersion: config.AtlantisVersion,