From 94d7315786489b87d492f8d6f864b9297da07521 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 15:12:14 -0400 Subject: [PATCH 01/20] build(deps): bump github.com/hashicorp/go-getter from 1.5.8 to 1.5.9 (#1850) Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.5.8 to 1.5.9. - [Release notes](https://github.com/hashicorp/go-getter/releases) - [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml) - [Commits](https://github.com/hashicorp/go-getter/compare/v1.5.8...v1.5.9) --- updated-dependencies: - dependency-name: github.com/hashicorp/go-getter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 5 ++--- go.sum | 8 ++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 04fbb7970b..8de41c4405 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/aws/aws-sdk-go v1.31.15 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/bradleyfalzon/ghinstallation/v2 v2.0.3 github.com/briandowns/spinner v0.0.0-20170614154858-48dbb65d7bd5 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc @@ -32,7 +33,6 @@ require ( github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.6 // indirect - github.com/google/go-github/v29 v29.0.2 // indirect github.com/google/go-github/v31 v31.0.0 github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.1.2-0.20200519141726-cb32006e483f // indirect @@ -41,7 +41,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.5.8 + github.com/hashicorp/go-getter v1.5.9 github.com/hashicorp/go-retryablehttp v0.6.8 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.3.0 @@ -120,7 +120,6 @@ require ( ) require ( - github.com/bradleyfalzon/ghinstallation/v2 v2.0.3 // indirect github.com/google/go-github/v39 v39.1.0 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect ) diff --git a/go.sum b/go.sum index abffc15587..01c7169a30 100644 --- a/go.sum +++ b/go.sum @@ -180,14 +180,11 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= -github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo= github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= github.com/google/go-github/v39 v39.1.0 h1:1vf4gM0D1e+Df2HMxaYC3+o9+Huj3ywGTtWc3VVYaDA= github.com/google/go-github/v39 v39.1.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -234,8 +231,8 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.5.8 h1:qx5CZXxXz5YFpALPkbf/F1iZZoRE+f6T1i/AWw/Zkic= -github.com/hashicorp/go-getter v1.5.8/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI= +github.com/hashicorp/go-getter v1.5.9 h1:b7ahZW50iQiUek/at3CvZhPK1/jiV6CtKcsJiR6E4R0= +github.com/hashicorp/go-getter v1.5.9/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= @@ -470,7 +467,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= From 515df4edb1041d9be9f581a8dbac96384b4ff41b Mon Sep 17 00:00:00 2001 From: rui Date: Sun, 17 Oct 2021 13:46:47 -0400 Subject: [PATCH 02/20] deps: terraform 1.0.9 (#1854) Signed-off-by: Rui Chen --- .circleci/config.yml | 2 +- Dockerfile | 2 +- testdrive/utils.go | 2 +- testing/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a1bb1a22c1..302f597e44 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ jobs: # We do this instead of setting --default-tf-version because setting # that flag starts the download asynchronously so we'd have a race # condition. - TERRAFORM_VERSION: 1.0.8 + TERRAFORM_VERSION: 1.0.9 steps: - checkout - run: make build-service diff --git a/Dockerfile b/Dockerfile index 09f3687fe0..da57e36918 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ghcr.io/runatlantis/atlantis-base:2021.08.31 # install terraform binaries -ENV DEFAULT_TERRAFORM_VERSION=1.0.8 +ENV DEFAULT_TERRAFORM_VERSION=1.0.9 # In the official Atlantis image we only have the latest of each Terraform version. RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.15 0.12.31 0.13.7 0.14.11 0.15.5 ${DEFAULT_TERRAFORM_VERSION}" && \ diff --git a/testdrive/utils.go b/testdrive/utils.go index a64b2c0754..592d5f1065 100644 --- a/testdrive/utils.go +++ b/testdrive/utils.go @@ -34,7 +34,7 @@ import ( ) const hashicorpReleasesURL = "https://releases.hashicorp.com" -const terraformVersion = "1.0.8" +const terraformVersion = "1.0.9" const ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb" const ngrokAPIURL = "localhost:41414" // We hope this isn't used. const atlantisPort = 4141 diff --git a/testing/Dockerfile b/testing/Dockerfile index e137e2fa93..9fef892cfa 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -1,7 +1,7 @@ FROM circleci/golang:1.17 # Install Terraform -ENV TERRAFORM_VERSION=1.0.8 +ENV TERRAFORM_VERSION=1.0.9 RUN curl -LOks https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \ sudo mkdir -p /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ sudo unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ From 571f91fbdab9cbf4cef107a043cfb41e5bf91272 Mon Sep 17 00:00:00 2001 From: Daniel Grimes Date: Sun, 17 Oct 2021 19:07:14 +0100 Subject: [PATCH 03/20] fix(azure): allow host to be specified in user_config for on premise installation (#1860) * add .devcontainer to .gitignore * allow AzureDevOps host to be specified in the user_config * fix spacing issues * gofmt * fixes to cmd and update to approach Co-authored-by: atlantisbot --- .gitignore | 1 + cmd/server.go | 9 +++++++++ server/server.go | 3 ++- server/user_config.go | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c23cbfed9c..a9ca864199 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ helm/test-values.yaml *.swp golangci-lint atlantis +.devcontainer \ No newline at end of file diff --git a/cmd/server.go b/cmd/server.go index cd869dbd0f..0699d5b825 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -41,6 +41,7 @@ const ( ADWebhookUserFlag = "azuredevops-webhook-user" ADTokenFlag = "azuredevops-token" // nolint: gosec ADUserFlag = "azuredevops-user" + ADHostnameFlag = "azuredevops-hostname" AllowForkPRsFlag = "allow-fork-prs" AllowRepoConfigFlag = "allow-repo-config" AtlantisURLFlag = "atlantis-url" @@ -106,6 +107,7 @@ const ( // NOTE: Must manually set these as defaults in the setDefaults function. DefaultADBasicUser = "" DefaultADBasicPassword = "" + DefaultADHostname = "dev.azure.com" DefaultAutoplanFileList = "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl" DefaultCheckoutStrategy = "branch" DefaultBitbucketBaseURL = bitbucketcloud.BaseURL @@ -139,6 +141,10 @@ var stringFlags = map[string]stringFlag{ description: "Azure DevOps basic HTTP authentication username for inbound webhooks.", defaultValue: "", }, + ADHostnameFlag: { + description: "Azure DevOps hostname to support cloud and self hosted instances.", + defaultValue: "dev.azure.com", + }, AtlantisURLFlag: { description: "URL that Atlantis can be reached at. Defaults to http://$(hostname):$port where $port is from --" + PortFlag + ". Supports a base path ex. https://example.com/basepath.", }, @@ -589,6 +595,9 @@ func (s *ServerCmd) run() error { } func (s *ServerCmd) setDefaults(c *server.UserConfig) { + if c.AzureDevOpsHostname == "" { + c.AzureDevOpsHostname = DefaultADHostname + } if c.AutoplanFileList == "" { c.AutoplanFileList = DefaultAutoplanFileList } diff --git a/server/server.go b/server/server.go index 5519ed18a8..9afab1c7f4 100644 --- a/server/server.go +++ b/server/server.go @@ -216,8 +216,9 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { } if userConfig.AzureDevopsUser != "" { supportedVCSHosts = append(supportedVCSHosts, models.AzureDevops) + var err error - azuredevopsClient, err = vcs.NewAzureDevopsClient("dev.azure.com", userConfig.AzureDevopsUser, userConfig.AzureDevopsToken) + azuredevopsClient, err = vcs.NewAzureDevopsClient(userConfig.AzureDevOpsHostname, userConfig.AzureDevopsUser, userConfig.AzureDevopsToken) if err != nil { return nil, err } diff --git a/server/user_config.go b/server/user_config.go index 4875ad7671..297b692886 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -17,6 +17,7 @@ type UserConfig struct { AzureDevopsUser string `mapstructure:"azuredevops-user"` AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` + AzureDevOpsHostname string `mapstructure:"azuredevops-hostname"` BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` BitbucketToken string `mapstructure:"bitbucket-token"` BitbucketUser string `mapstructure:"bitbucket-user"` From 8132efed9d80f1e92a7c4ae0b726b328f758bc95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Oct 2021 10:55:55 -0400 Subject: [PATCH 04/20] build(deps): bump github.com/go-test/deep from 1.0.7 to 1.0.8 (#1862) Bumps [github.com/go-test/deep](https://github.com/go-test/deep) from 1.0.7 to 1.0.8. - [Release notes](https://github.com/go-test/deep/releases) - [Changelog](https://github.com/go-test/deep/blob/master/CHANGES.md) - [Commits](https://github.com/go-test/deep/compare/v1.0.7...v1.0.8) --- updated-dependencies: - dependency-name: github.com/go-test/deep dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8de41c4405..183cd2639d 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/go-ozzo/ozzo-validation v0.0.0-20170913164239-85dcd8368eba github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect - github.com/go-test/deep v1.0.7 + github.com/go-test/deep v1.0.8 github.com/golang-jwt/jwt/v4 v4.1.0 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect diff --git a/go.sum b/go.sum index 01c7169a30..96c7b848a6 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,8 @@ github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rm github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= -github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= From 8093b8864a3bab46a36ea3860d99e379fc603208 Mon Sep 17 00:00:00 2001 From: rui Date: Tue, 19 Oct 2021 12:35:10 -0400 Subject: [PATCH 05/20] deps: update conftest to 0.28.1 for atlantis img (#1864) Signed-off-by: Rui Chen --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index da57e36918..484c4bedc5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.15 0.12.31 0.13.7 0.1 done && \ ln -s /usr/local/bin/tf/versions/${DEFAULT_TERRAFORM_VERSION}/terraform /usr/local/bin/terraform -ENV DEFAULT_CONFTEST_VERSION=0.25.0 +ENV DEFAULT_CONFTEST_VERSION=0.28.1 RUN AVAILABLE_CONFTEST_VERSIONS="${DEFAULT_CONFTEST_VERSION}" && \ for VERSION in ${AVAILABLE_CONFTEST_VERSIONS}; do \ From d01796b9d9bf696fd8b42047fcdbd5c3709f995f Mon Sep 17 00:00:00 2001 From: Nish Krishnan Date: Tue, 19 Oct 2021 13:51:22 -0700 Subject: [PATCH 06/20] feat: filter out atlantis/apply from mergeability clause (#1856) Filter out atlantis apply status during mergeability check. --- .../events/events_controller_e2e_test.go | 3 +- server/controllers/github_app_controller.go | 3 +- server/events/commit_status_updater.go | 26 ++-- server/events/commit_status_updater_test.go | 19 ++- server/events/vcs/github_client.go | 92 ++++++++++-- .../events/vcs/github_client_internal_test.go | 4 +- server/events/vcs/github_client_test.go | 138 ++++++++++++++++-- server/events/vcs/github_credentials_test.go | 6 +- server/events/vcs/status.go | 39 +++++ server/events/vcs/status_test.go | 32 ++++ server/server.go | 5 +- 11 files changed, 312 insertions(+), 55 deletions(-) create mode 100644 server/events/vcs/status.go create mode 100644 server/events/vcs/status_test.go diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go index 6db49d49a0..7975a168b6 100644 --- a/server/controllers/events/events_controller_e2e_test.go +++ b/server/controllers/events/events_controller_e2e_test.go @@ -29,6 +29,7 @@ import ( "github.com/runatlantis/atlantis/server/events/mocks" "github.com/runatlantis/atlantis/server/events/mocks/matchers" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks" "github.com/runatlantis/atlantis/server/events/webhooks" "github.com/runatlantis/atlantis/server/events/yaml" @@ -811,7 +812,7 @@ func setupE2E(t *testing.T, repoDir string) (events_controllers.VCSEventsControl // Mocks. e2eVCSClient := vcsmocks.NewMockClient() - e2eStatusUpdater := &events.DefaultCommitStatusUpdater{Client: e2eVCSClient} + e2eStatusUpdater := &events.DefaultCommitStatusUpdater{Client: e2eVCSClient, TitleBuilder: vcs.StatusTitleBuilder{TitlePrefix: "atlantis"}} e2eGithubGetter := mocks.NewMockGithubPullGetter() e2eGitlabGetter := mocks.NewMockGitlabMergeRequestGetter() diff --git a/server/controllers/github_app_controller.go b/server/controllers/github_app_controller.go index d8808cd835..df8b24de30 100644 --- a/server/controllers/github_app_controller.go +++ b/server/controllers/github_app_controller.go @@ -18,6 +18,7 @@ type GithubAppController struct { GithubSetupComplete bool GithubHostname string GithubOrg string + GithubStatusName string } type githubWebhook struct { @@ -55,7 +56,7 @@ func (g *GithubAppController) ExchangeCode(w http.ResponseWriter, r *http.Reques g.Logger.Debug("Exchanging GitHub app code for app credentials") creds := &vcs.GithubAnonymousCredentials{} - client, err := vcs.NewGithubClient(g.GithubHostname, creds, g.Logger) + client, err := vcs.NewGithubClient(g.GithubHostname, creds, g.Logger, g.GithubStatusName) if err != nil { g.respond(w, logging.Error, http.StatusInternalServerError, "Failed to exchange code for github app: %s", err) return diff --git a/server/events/commit_status_updater.go b/server/events/commit_status_updater.go index d5be3b0910..f41ec0a2b8 100644 --- a/server/events/commit_status_updater.go +++ b/server/events/commit_status_updater.go @@ -28,10 +28,10 @@ import ( type CommitStatusUpdater interface { // UpdateCombined updates the combined status of the head commit of pull. // A combined status represents all the projects modified in the pull. - UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) error + UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName models.CommandName) error // UpdateCombinedCount updates the combined status to reflect the // numSuccess out of numTotal. - UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) error + UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName models.CommandName, numSuccess int, numTotal int) error // UpdateProject sets the commit status for the project represented by // ctx. UpdateProject(ctx models.ProjectCommandContext, cmdName models.CommandName, status models.CommitStatus, url string) error @@ -39,13 +39,12 @@ type CommitStatusUpdater interface { // DefaultCommitStatusUpdater implements CommitStatusUpdater. type DefaultCommitStatusUpdater struct { - Client vcs.Client - // StatusName is the name used to identify Atlantis when creating PR statuses. - StatusName string + Client vcs.Client + TitleBuilder vcs.StatusTitleBuilder } -func (d *DefaultCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName) error { - src := fmt.Sprintf("%s/%s", d.StatusName, command.String()) +func (d *DefaultCommitStatusUpdater) UpdateCombined(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName models.CommandName) error { + src := d.TitleBuilder.Build(cmdName.String()) var descripWords string switch status { case models.PendingCommitStatus: @@ -55,15 +54,15 @@ func (d *DefaultCommitStatusUpdater) UpdateCombined(repo models.Repo, pull model case models.SuccessCommitStatus: descripWords = "succeeded." } - descrip := fmt.Sprintf("%s %s", strings.Title(command.String()), descripWords) + descrip := fmt.Sprintf("%s %s", strings.Title(cmdName.String()), descripWords) return d.Client.UpdateStatus(repo, pull, status, src, descrip, "") } -func (d *DefaultCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, command models.CommandName, numSuccess int, numTotal int) error { - src := fmt.Sprintf("%s/%s", d.StatusName, command.String()) +func (d *DefaultCommitStatusUpdater) UpdateCombinedCount(repo models.Repo, pull models.PullRequest, status models.CommitStatus, cmdName models.CommandName, numSuccess int, numTotal int) error { + src := d.TitleBuilder.Build(cmdName.String()) cmdVerb := "unknown" - switch command { + switch cmdName { case models.PlanCommand: cmdVerb = "planned" case models.PolicyCheckCommand: @@ -80,7 +79,10 @@ func (d *DefaultCommitStatusUpdater) UpdateProject(ctx models.ProjectCommandCont if projectID == "" { projectID = fmt.Sprintf("%s/%s", ctx.RepoRelDir, ctx.Workspace) } - src := fmt.Sprintf("%s/%s: %s", d.StatusName, cmdName.String(), projectID) + + src := d.TitleBuilder.Build(cmdName.String(), vcs.StatusTitleOptions{ + ProjectName: projectID, + }) var descripWords string switch status { case models.PendingCommitStatus: diff --git a/server/events/commit_status_updater_test.go b/server/events/commit_status_updater_test.go index 582daf2586..aa2c658c06 100644 --- a/server/events/commit_status_updater_test.go +++ b/server/events/commit_status_updater_test.go @@ -20,6 +20,7 @@ import ( . "github.com/petergtz/pegomock" "github.com/runatlantis/atlantis/server/events" "github.com/runatlantis/atlantis/server/events/models" + "github.com/runatlantis/atlantis/server/events/vcs" "github.com/runatlantis/atlantis/server/events/vcs/mocks" . "github.com/runatlantis/atlantis/testing" ) @@ -66,7 +67,9 @@ func TestUpdateCombined(t *testing.T) { t.Run(c.expDescrip, func(t *testing.T) { RegisterMockTestingT(t) client := mocks.NewMockClient() - s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis"} + + titleBuilder := vcs.StatusTitleBuilder{TitlePrefix: "atlantis"} + s := events.DefaultCommitStatusUpdater{Client: client, TitleBuilder: titleBuilder} err := s.UpdateCombined(models.Repo{}, models.PullRequest{}, c.status, c.command) Ok(t, err) @@ -132,11 +135,12 @@ func TestUpdateCombinedCount(t *testing.T) { t.Run(c.expDescrip, func(t *testing.T) { RegisterMockTestingT(t) client := mocks.NewMockClient() - s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis-test"} + titleBuilder := vcs.StatusTitleBuilder{TitlePrefix: "atlantis-test"} + s := events.DefaultCommitStatusUpdater{Client: client, TitleBuilder: titleBuilder} err := s.UpdateCombinedCount(models.Repo{}, models.PullRequest{}, c.status, c.command, c.numSuccess, c.numTotal) Ok(t, err) - expSrc := fmt.Sprintf("%s/%s", s.StatusName, c.command) + expSrc := fmt.Sprintf("%s/%s", titleBuilder.TitlePrefix, c.command) client.VerifyWasCalledOnce().UpdateStatus(models.Repo{}, models.PullRequest{}, c.status, expSrc, c.expDescrip, "") }) } @@ -169,7 +173,8 @@ func TestDefaultCommitStatusUpdater_UpdateProjectSrc(t *testing.T) { for _, c := range cases { t.Run(c.expSrc, func(t *testing.T) { client := mocks.NewMockClient() - s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis"} + titleBuilder := vcs.StatusTitleBuilder{TitlePrefix: "atlantis"} + s := events.DefaultCommitStatusUpdater{Client: client, TitleBuilder: titleBuilder} err := s.UpdateProject(models.ProjectCommandContext{ ProjectName: c.projectName, RepoRelDir: c.repoRelDir, @@ -227,7 +232,8 @@ func TestDefaultCommitStatusUpdater_UpdateProject(t *testing.T) { for _, c := range cases { t.Run(c.expDescrip, func(t *testing.T) { client := mocks.NewMockClient() - s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "atlantis"} + titleBuilder := vcs.StatusTitleBuilder{TitlePrefix: "atlantis"} + s := events.DefaultCommitStatusUpdater{Client: client, TitleBuilder: titleBuilder} err := s.UpdateProject(models.ProjectCommandContext{ RepoRelDir: ".", Workspace: "default", @@ -245,7 +251,8 @@ func TestDefaultCommitStatusUpdater_UpdateProject(t *testing.T) { func TestDefaultCommitStatusUpdater_UpdateProjectCustomStatusName(t *testing.T) { RegisterMockTestingT(t) client := mocks.NewMockClient() - s := events.DefaultCommitStatusUpdater{Client: client, StatusName: "custom"} + titleBuilder := vcs.StatusTitleBuilder{TitlePrefix: "custom"} + s := events.DefaultCommitStatusUpdater{Client: client, TitleBuilder: titleBuilder} err := s.UpdateProject(models.ProjectCommandContext{ RepoRelDir: ".", Workspace: "default", diff --git a/server/events/vcs/github_client.go b/server/events/vcs/github_client.go index 117a2d3fcb..d8c310f343 100644 --- a/server/events/vcs/github_client.go +++ b/server/events/vcs/github_client.go @@ -33,15 +33,18 @@ import ( // maxCommentLength is the maximum number of chars allowed in a single comment // by GitHub. -const maxCommentLength = 65536 +const ( + maxCommentLength = 65536 +) // GithubClient is used to perform GitHub actions. type GithubClient struct { - user string - client *github.Client - v4MutateClient *graphql.Client - ctx context.Context - logger logging.SimpleLogging + user string + client *github.Client + v4MutateClient *graphql.Client + ctx context.Context + logger logging.SimpleLogging + statusTitleMatcher StatusTitleMatcher } // GithubAppTemporarySecrets holds app credentials obtained from github after creation. @@ -59,7 +62,7 @@ type GithubAppTemporarySecrets struct { } // NewGithubClient returns a valid GitHub client. -func NewGithubClient(hostname string, credentials GithubCredentials, logger logging.SimpleLogging) (*GithubClient, error) { +func NewGithubClient(hostname string, credentials GithubCredentials, logger logging.SimpleLogging, commitStatusPrefix string) (*GithubClient, error) { transport, err := credentials.Client() if err != nil { return nil, errors.Wrap(err, "error initializing github authentication transport") @@ -99,11 +102,12 @@ func NewGithubClient(hostname string, credentials GithubCredentials, logger logg return nil, errors.Wrap(err, "getting user") } return &GithubClient{ - user: user, - client: client, - v4MutateClient: v4MutateClient, - ctx: context.Background(), - logger: logger, + user: user, + client: client, + v4MutateClient: v4MutateClient, + ctx: context.Background(), + logger: logger, + statusTitleMatcher: StatusTitleMatcher{TitlePrefix: commitStatusPrefix}, }, nil } @@ -280,8 +284,40 @@ func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest // hooks. Merging is allowed (green box). // See: https://github.com/octokit/octokit.net/issues/1763 if state != "clean" && state != "unstable" && state != "has_hooks" { + + if state != "blocked" { + return false, nil + } + + return g.getSupplementalMergeability(repo, pull) + } + return true, nil +} + +// Checks to make sure that all statuses are passing except the atlantis/apply. If we only rely on GetMergeableState, +// we can run into issues where if an apply failed, we can never apply again due to mergeability failures. +func (g *GithubClient) getSupplementalMergeability(repo models.Repo, pull models.PullRequest) (bool, error) { + statuses, err := g.getRepoStatuses(repo, pull) + + if err != nil { + return false, errors.Wrapf(err, "fetching repo statuses for repo: %s, and pull number: %d", repo.FullName, pull.Num) + } + + for _, status := range statuses { + state := status.GetState() + + if g.statusTitleMatcher.MatchesCommand(status.GetContext(), "apply") || + state == "success" { + continue + + } + + // we either have a failure or a pending status check + // hence the PR is not mergeable return false, nil } + + // all our status checks are successful by our definition, return true, nil } @@ -312,6 +348,38 @@ func (g *GithubClient) GetPullRequest(repo models.Repo, num int) (*github.PullRe return pull, err } +func (g *GithubClient) getRepoStatuses(repo models.Repo, pull models.PullRequest) ([]*github.RepoStatus, error) { + // Get Combined statuses + + nextPage := 0 + + var result []*github.RepoStatus + + for { + opts := github.ListOptions{ + // explicit default + // https://developer.github.com/v3/repos/statuses/#list-commit-statuses-for-a-reference + PerPage: 100, + } + if nextPage != 0 { + opts.Page = nextPage + } + + combinedStatus, response, err := g.client.Repositories.GetCombinedStatus(g.ctx, repo.Owner, repo.Name, pull.HeadCommit, &opts) + result = append(result, combinedStatus.Statuses...) + + if err != nil { + return nil, err + } + if response.NextPage == 0 { + break + } + nextPage = response.NextPage + } + + return result, nil +} + // UpdateStatus updates the status badge on the pull request. // See https://github.com/blog/1227-commit-status-api. func (g *GithubClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error { diff --git a/server/events/vcs/github_client_internal_test.go b/server/events/vcs/github_client_internal_test.go index ebe039d319..70b79912ea 100644 --- a/server/events/vcs/github_client_internal_test.go +++ b/server/events/vcs/github_client_internal_test.go @@ -22,14 +22,14 @@ import ( // If the hostname is github.com, should use normal BaseURL. func TestNewGithubClient_GithubCom(t *testing.T) { - client, err := NewGithubClient("github.com", &GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := NewGithubClient("github.com", &GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) Equals(t, "https://api.github.com/", client.client.BaseURL.String()) } // If the hostname is a non-github hostname should use the right BaseURL. func TestNewGithubClient_NonGithub(t *testing.T) { - client, err := NewGithubClient("example.com", &GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := NewGithubClient("example.com", &GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) Equals(t, "https://example.com/api/v3/", client.client.BaseURL.String()) // If possible in the future, test the GraphQL client's URL as well. But at the diff --git a/server/events/vcs/github_client_test.go b/server/events/vcs/github_client_test.go index bb4f55703e..f31de0d6a9 100644 --- a/server/events/vcs/github_client_test.go +++ b/server/events/vcs/github_client_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "net/http" "net/http/httptest" "net/url" @@ -62,7 +63,7 @@ func TestGithubClient_GetModifiedFiles(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logger) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logger, "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -117,7 +118,7 @@ func TestGithubClient_GetModifiedFilesMovedFile(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -211,7 +212,7 @@ func TestGithubClient_PaginatesComments(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -300,7 +301,7 @@ func TestGithubClient_HideOldComments(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -366,7 +367,7 @@ func TestGithubClient_UpdateStatus(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -452,7 +453,7 @@ func TestGithubClient_PullIsApproved(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -486,10 +487,6 @@ func TestGithubClient_PullIsMergeable(t *testing.T) { "unknown", false, }, - { - "blocked", - false, - }, { "behind", false, @@ -543,7 +540,7 @@ func TestGithubClient_PullIsMergeable(t *testing.T) { })) testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -566,6 +563,115 @@ func TestGithubClient_PullIsMergeable(t *testing.T) { } } +func TestGithubClient_PullisMergeable_BlockedStatus(t *testing.T) { + + // Use a real GitHub json response and edit the mergeable_state field. + jsBytes, err := ioutil.ReadFile("fixtures/github-pull-request.json") + Ok(t, err) + json := string(jsBytes) + + pullResponse := strings.Replace(json, + `"mergeable_state": "clean"`, + fmt.Sprintf(`"mergeable_state": "%s"`, "blocked"), + 1, + ) + + combinedStatusJSON := `{ + "state": "success", + "statuses": [%s] + }` + statusJSON := `{ + "url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e", + "avatar_url": "https://github.com/images/error/other_user_happy.gif", + "id": 2, + "node_id": "MDY6U3RhdHVzMg==", + "state": "%s", + "description": "Testing has completed successfully", + "target_url": "https://ci.example.com/2000/output", + "context": "%s", + "created_at": "2012-08-20T01:19:13Z", + "updated_at": "2012-08-20T01:19:13Z" + }` + + cases := []struct { + description string + statuses []string + expMergeable bool + }{ + { + "apply-failure", + []string{ + fmt.Sprintf(statusJSON, "failure", "atlantis/apply"), + }, + true, + }, + { + "apply-project-failure", + []string{ + fmt.Sprintf(statusJSON, "failure", "atlantis/apply: terraform_cloud_workspace"), + }, + true, + }, + { + "sq-pending+owners-failure", + []string{ + fmt.Sprintf(statusJSON, "failure", "atlantis/plan"), + fmt.Sprintf(statusJSON, "failure", "atlantis/apply"), + }, + false, + }, + } + + for _, c := range cases { + + t.Run("blocked/"+c.description, func(t *testing.T) { + testServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.RequestURI { + case "/api/v3/repos/owner/repo/commits/2/status?per_page=100": + _, _ = w.Write([]byte( + fmt.Sprintf(combinedStatusJSON, strings.Join(c.statuses, ",")), + )) // nolint: errcheck + return + case "/api/v3/repos/owner/repo/pulls/1": + w.Write([]byte(pullResponse)) // nolint: errcheck + return + default: + t.Errorf("got unexpected request at %q", r.RequestURI) + http.Error(w, "not found", http.StatusNotFound) + return + } + })) + + defer testServer.Close() + + testServerURL, err := url.Parse(testServer.URL) + Ok(t, err) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") + Ok(t, err) + defer disableSSLVerification()() + + actMergeable, err := client.PullIsMergeable(models.Repo{ + FullName: "owner/repo", + Owner: "owner", + Name: "repo", + CloneURL: "", + SanitizedCloneURL: "", + VCSHost: models.VCSHost{ + Type: models.Github, + Hostname: "github.com", + }, + }, models.PullRequest{ + Num: 1, + HeadCommit: "2", + }) + Ok(t, err) + Equals(t, c.expMergeable, actMergeable) + }) + } + +} + func TestGithubClient_MergePullHandlesError(t *testing.T) { cases := []struct { code int @@ -625,7 +731,7 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -748,7 +854,7 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() @@ -776,7 +882,7 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) { } func TestGithubClient_MarkdownPullLink(t *testing.T) { - client, err := vcs.NewGithubClient("hostname", &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient("hostname", &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) pull := models.PullRequest{Num: 1} s, _ := client.MarkdownPullLink(pull) @@ -831,7 +937,7 @@ func TestGithubClient_SplitComments(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() pull := models.PullRequest{Num: 1} @@ -889,7 +995,7 @@ func TestGithubClient_Retry404(t *testing.T) { testServerURL, err := url.Parse(testServer.URL) Ok(t, err) - client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t)) + client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, logging.NewNoopLogger(t), "atlantis") Ok(t, err) defer disableSSLVerification()() repo := models.Repo{ diff --git a/server/events/vcs/github_credentials_test.go b/server/events/vcs/github_credentials_test.go index a85d8d2d95..a6951c1db5 100644 --- a/server/events/vcs/github_credentials_test.go +++ b/server/events/vcs/github_credentials_test.go @@ -15,7 +15,7 @@ func TestGithubClient_GetUser_AppSlug(t *testing.T) { Ok(t, err) anonCreds := &vcs.GithubAnonymousCredentials{} - anonClient, err := vcs.NewGithubClient(testServer, anonCreds, logging.NewNoopLogger(t)) + anonClient, err := vcs.NewGithubClient(testServer, anonCreds, logging.NewNoopLogger(t), "atlantis") Ok(t, err) tempSecrets, err := anonClient.ExchangeCode("good-code") Ok(t, err) @@ -39,7 +39,7 @@ func TestGithubClient_AppAuthentication(t *testing.T) { Ok(t, err) anonCreds := &vcs.GithubAnonymousCredentials{} - anonClient, err := vcs.NewGithubClient(testServer, anonCreds, logging.NewNoopLogger(t)) + anonClient, err := vcs.NewGithubClient(testServer, anonCreds, logging.NewNoopLogger(t), "atlantis") Ok(t, err) tempSecrets, err := anonClient.ExchangeCode("good-code") Ok(t, err) @@ -49,7 +49,7 @@ func TestGithubClient_AppAuthentication(t *testing.T) { Key: []byte(fixtures.GithubPrivateKey), Hostname: testServer, } - _, err = vcs.NewGithubClient(testServer, appCreds, logging.NewNoopLogger(t)) + _, err = vcs.NewGithubClient(testServer, appCreds, logging.NewNoopLogger(t), "atlantis") Ok(t, err) token, err := appCreds.GetToken() diff --git a/server/events/vcs/status.go b/server/events/vcs/status.go new file mode 100644 index 0000000000..929d3930e1 --- /dev/null +++ b/server/events/vcs/status.go @@ -0,0 +1,39 @@ +package vcs + +import ( + "fmt" + "strings" +) + +type StatusTitleMatcher struct { + TitlePrefix string +} + +func (m StatusTitleMatcher) MatchesCommand(title string, command string) bool { + return strings.HasPrefix(title, fmt.Sprintf("%s/%s", m.TitlePrefix, command)) +} + +type StatusTitleBuilder struct { + TitlePrefix string +} + +type StatusTitleOptions struct { + ProjectName string +} + +func (b StatusTitleBuilder) Build(command string, options ...StatusTitleOptions) string { + src := fmt.Sprintf("%s/%s", b.TitlePrefix, command) + + var projectName string + for _, opt := range options { + if opt.ProjectName != "" { + projectName = opt.ProjectName + } + } + + if projectName != "" { + src = fmt.Sprintf("%s: %s", src, projectName) + } + + return src +} diff --git a/server/events/vcs/status_test.go b/server/events/vcs/status_test.go new file mode 100644 index 0000000000..144e37480b --- /dev/null +++ b/server/events/vcs/status_test.go @@ -0,0 +1,32 @@ +package vcs_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/events/vcs" + "github.com/stretchr/testify/assert" +) + +func TestMatches(t *testing.T) { + + t.Run("in sync with builder", func(t *testing.T) { + titlePrefix := "atlantis-test" + command := "apply" + builder := vcs.StatusTitleBuilder{TitlePrefix: titlePrefix} + matcher := vcs.StatusTitleMatcher{TitlePrefix: titlePrefix} + + title := builder.Build(command) + + assert.True(t, matcher.MatchesCommand(title, command)) + }) + + t.Run("incorrect command", func(t *testing.T) { + titlePrefix := "atlantis-test" + builder := vcs.StatusTitleBuilder{TitlePrefix: titlePrefix} + matcher := vcs.StatusTitleMatcher{TitlePrefix: titlePrefix} + + title := builder.Build("apply") + + assert.False(t, matcher.MatchesCommand(title, "plan")) + }) +} diff --git a/server/server.go b/server/server.go index 9afab1c7f4..e14158ebff 100644 --- a/server/server.go +++ b/server/server.go @@ -179,7 +179,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { } var err error - githubClient, err = vcs.NewGithubClient(userConfig.GithubHostname, githubCredentials, logger) + githubClient, err = vcs.NewGithubClient(userConfig.GithubHostname, githubCredentials, logger, userConfig.VCSStatusName) if err != nil { return nil, err } @@ -272,7 +272,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { return nil, errors.Wrap(err, "initializing webhooks") } vcsClient := vcs.NewClientProxy(githubClient, gitlabClient, bitbucketCloudClient, bitbucketServerClient, azuredevopsClient) - commitStatusUpdater := &events.DefaultCommitStatusUpdater{Client: vcsClient, StatusName: userConfig.VCSStatusName} + commitStatusUpdater := &events.DefaultCommitStatusUpdater{Client: vcsClient, TitleBuilder: vcs.StatusTitleBuilder{TitlePrefix: userConfig.VCSStatusName}} binDir, err := mkSubDir(userConfig.DataDir, BinDirName) @@ -653,6 +653,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { GithubSetupComplete: githubAppEnabled, GithubHostname: userConfig.GithubHostname, GithubOrg: userConfig.GithubOrg, + GithubStatusName: userConfig.VCSStatusName, } return &Server{ From cbf35ca0edaf1321c6726c39b3c078b632395bc2 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Fri, 22 Oct 2021 05:58:30 +0800 Subject: [PATCH 07/20] feat: add BasicAuth Support to Atlantis ServeHTTP (#1777) * Add BasicAuth Support to Atlantis ServeHTTP * Added Security notes Co-authored-by: xmurias --- cmd/server.go | 24 +++++++++++++++++++ runatlantis.io/docs/security.md | 11 ++++++++- server/middleware.go | 41 +++++++++++++++++++++++++++++---- server/server.go | 9 ++++++-- server/user_config.go | 3 +++ 5 files changed, 80 insertions(+), 8 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index 0699d5b825..882ac23ab5 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -103,6 +103,9 @@ const ( TFEHostnameFlag = "tfe-hostname" TFETokenFlag = "tfe-token" WriteGitCredsFlag = "write-git-creds" + WebBasicAuthFlag = "web-basic-auth" + WebUsernameFlag = "web-username" + WebPasswordFlag = "web-password" // NOTE: Must manually set these as defaults in the setDefaults function. DefaultADBasicUser = "" @@ -120,6 +123,9 @@ const ( DefaultTFDownloadURL = "https://releases.hashicorp.com" DefaultTFEHostname = "app.terraform.io" DefaultVCSStatusName = "atlantis" + DefaultWebBasicAuth = false + DefaultWebUsername = "atlantis" + DefaultWebPassword = "atlantis" ) var stringFlags = map[string]stringFlag{ @@ -287,6 +293,14 @@ var stringFlags = map[string]stringFlag{ description: "Name used to identify Atlantis for pull request statuses.", defaultValue: DefaultVCSStatusName, }, + WebUsernameFlag: { + description: "Username used for Web Basic Authentication on Atlantis HTTP Middleware", + defaultValue: DefaultWebUsername, + }, + WebPasswordFlag: { + description: "Password used for Web Basic Authentication on Atlantis HTTP Middleware", + defaultValue: DefaultWebPassword, + }, } var boolFlags = map[string]boolFlag{ @@ -385,6 +399,10 @@ var boolFlags = map[string]boolFlag{ description: "Skips cloning the PR repo if there are no projects were changed in the PR.", defaultValue: false, }, + WebBasicAuthFlag: { + description: "Switches on or off the Basic Authentication on the HTTP Middleware interface", + defaultValue: DefaultWebBasicAuth, + }, } var intFlags = map[string]intFlag{ ParallelPoolSize: { @@ -634,6 +652,12 @@ func (s *ServerCmd) setDefaults(c *server.UserConfig) { if c.TFEHostname == "" { c.TFEHostname = DefaultTFEHostname } + if c.WebUsername == "" { + c.WebUsername = DefaultWebUsername + } + if c.WebPassword == "" { + c.WebPassword = DefaultWebPassword + } } func (s *ServerCmd) validate(userConfig server.UserConfig) error { diff --git a/runatlantis.io/docs/security.md b/runatlantis.io/docs/security.md index 4793190afe..a1cfa57812 100644 --- a/runatlantis.io/docs/security.md +++ b/runatlantis.io/docs/security.md @@ -34,7 +34,7 @@ To prevent this, allowlist [Bitbucket's IP addresses](https://confluence.atlassi ## Mitigations ### Don't Use On Public Repos -Because anyone can comment on public pull requests, even with all the security mitigations available, it's still dangerous to run Atlantis on public repos until Atlantis gets an authentication system. +Because anyone can comment on public pull requests, even with all the security mitigations available, it's still dangerous to run Atlantis on public repos without proper configuration of the security settings. ### Don't Use `--allow-fork-prs` If you're running on a public repo (which isn't recommended, see above) you shouldn't set `--allow-fork-prs` (defaults to false) @@ -79,3 +79,12 @@ Azure DevOps supports sending a basic authentication header in all webhook event If you're using webhook secrets but your traffic is over HTTP then the webhook secrets could be stolen. Enable SSL/HTTPS using the `--ssl-cert-file` and `--ssl-key-file` flags. + +### Enable Authentication on Atlantis Web Server +It is very reccomended to enable authentication in the web service. Enable BasicAuth using the `--web-basic-auth=true` and setup a username and a password using `--web-username=yourUsername` and `--web-password=yourPassword` flags. + +You can also pass these as environment variables `ATLANTIS_WEB_BASIC_AUTH=true` `ATLANTIS_WEB_USERNAME=yourUsername` and `ATLANTIS_WEB_PASSWORD=yourPassword`. + +::tip Tip +We do encourage the usage of complex passwords in order to prevent basic bruteforcing attacks. +::: \ No newline at end of file diff --git a/server/middleware.go b/server/middleware.go index 5aee2ebb6d..4a8ec444d4 100644 --- a/server/middleware.go +++ b/server/middleware.go @@ -21,18 +21,49 @@ import ( ) // NewRequestLogger creates a RequestLogger. -func NewRequestLogger(logger logging.SimpleLogging) *RequestLogger { - return &RequestLogger{logger} +func NewRequestLogger(s *Server) *RequestLogger { + return &RequestLogger{ + s.Logger, + s.WebAuthentication, + s.WebUsername, + s.WebPassword, + } } -// RequestLogger logs requests and their response codes. +// RequestLogger logs requests and their response codes +// as well as handle the basicauth on the requests type RequestLogger struct { - logger logging.SimpleLogging + logger logging.SimpleLogging + WebAuthentication bool + WebUsername string + WebPassword string } // ServeHTTP implements the middleware function. It logs all requests at DEBUG level. func (l *RequestLogger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { l.logger.Debug("%s %s – from %s", r.Method, r.URL.RequestURI(), r.RemoteAddr) - next(rw, r) + allowed := false + if r.URL.Path == "/events" || !l.WebAuthentication { + allowed = true + } else { + user, pass, ok := r.BasicAuth() + if ok { + r.SetBasicAuth(user, pass) + l.logger.Debug("user: %s / pass: %s >> url: %s", user, pass, r.URL.RequestURI()) + if user == l.WebUsername && pass == l.WebPassword { + l.logger.Debug("[VALID] user: %s / pass: %s >> url: %s", user, pass, r.URL.RequestURI()) + allowed = true + } else { + allowed = false + l.logger.Info("[INVALID] user: %s / pass: %s >> url: %s", user, pass, r.URL.RequestURI()) + } + } + } + if !allowed { + rw.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`) + http.Error(rw, "Unauthorized", http.StatusUnauthorized) + } else { + next(rw, r) + } l.logger.Debug("%s %s – respond HTTP %d", r.Method, r.URL.RequestURI(), rw.(negroni.ResponseWriter).Status()) } diff --git a/server/server.go b/server/server.go index e14158ebff..5f2502b9e8 100644 --- a/server/server.go +++ b/server/server.go @@ -97,6 +97,9 @@ type Server struct { SSLCertFile string SSLKeyFile string Drainer *events.Drainer + WebAuthentication bool + WebUsername string + WebPassword string } // Config holds config for server that isn't passed in by the user. @@ -655,7 +658,6 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { GithubOrg: userConfig.GithubOrg, GithubStatusName: userConfig.VCSStatusName, } - return &Server{ AtlantisVersion: config.AtlantisVersion, AtlantisURL: parsedURL, @@ -675,6 +677,9 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { SSLKeyFile: userConfig.SSLKeyFile, SSLCertFile: userConfig.SSLCertFile, Drainer: drainer, + WebAuthentication: userConfig.WebBasicAuth, + WebUsername: userConfig.WebUsername, + WebPassword: userConfig.WebPassword, }, nil } @@ -699,7 +704,7 @@ func (s *Server) Start() error { PrintStack: false, StackAll: false, StackSize: 1024 * 8, - }, NewRequestLogger(s.Logger)) + }, NewRequestLogger(s)) n.UseHandler(s.Router) defer s.Logger.Flush() diff --git a/server/user_config.go b/server/user_config.go index 297b692886..13d7071e62 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -87,6 +87,9 @@ type UserConfig struct { VCSStatusName string `mapstructure:"vcs-status-name"` DefaultTFVersion string `mapstructure:"default-tf-version"` Webhooks []WebhookConfig `mapstructure:"webhooks"` + WebBasicAuth bool `mapstructure:"web-basic-auth"` + WebUsername string `mapstructure:"web-username"` + WebPassword string `mapstructure:"web-password"` WriteGitCreds bool `mapstructure:"write-git-creds"` } From a148eb80a812daf2cdc39e301f5610d374146fea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:41:56 -0400 Subject: [PATCH 08/20] build(deps): bump github.com/mcdafydd/go-azuredevops (#1867) Bumps [github.com/mcdafydd/go-azuredevops](https://github.com/mcdafydd/go-azuredevops) from 0.12.0 to 0.12.1. - [Release notes](https://github.com/mcdafydd/go-azuredevops/releases) - [Commits](https://github.com/mcdafydd/go-azuredevops/compare/v0.12.0...v0.12.1) --- updated-dependencies: - dependency-name: github.com/mcdafydd/go-azuredevops dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 183cd2639d..e716c30324 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,7 @@ require ( github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-isatty v0.0.12 // indirect - github.com/mcdafydd/go-azuredevops v0.12.0 + github.com/mcdafydd/go-azuredevops v0.12.1 github.com/microcosm-cc/bluemonday v1.0.15 github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 github.com/mitchellh/copystructure v1.0.0 // indirect diff --git a/go.sum b/go.sum index 96c7b848a6..5185676f3c 100644 --- a/go.sum +++ b/go.sum @@ -314,8 +314,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mcdafydd/go-azuredevops v0.12.0 h1:CmG9uheFF6M3WnSykVNVLxR7zXrtg4p3pE2/lNDnPEE= -github.com/mcdafydd/go-azuredevops v0.12.0/go.mod h1:B4UDyn7WEj1/97f45j3VnzEfkWKe05+/dCcAPdOET4A= +github.com/mcdafydd/go-azuredevops v0.12.1 h1:WxwLVyGuJ8oL7uWQp1/J6GefX1wMQQZUHWRGsrm+uE8= +github.com/mcdafydd/go-azuredevops v0.12.1/go.mod h1:B4UDyn7WEj1/97f45j3VnzEfkWKe05+/dCcAPdOET4A= github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY= github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= From 4248e2ebf422a2082b151af9810192b45d96fb76 Mon Sep 17 00:00:00 2001 From: Daniel Grimes Date: Tue, 26 Oct 2021 18:34:47 +0100 Subject: [PATCH 09/20] fix(azure): allow correct path to be derived for on premise installation (#1863) * add .devcontainer to .gitignore * allow AzureDevOps host to be specified in the user_config * fix spacing issues * gofmt * fixes to cmd and update to approach * add specific self host fixtures * add specific self host parser tests * update code to azure self hosted devops * go fmt Co-authored-by: atlantisbot --- server/events/event_parser.go | 23 +++- server/events/event_parser_test.go | 176 +++++++++++++++++++++++++ server/events/vcs/fixtures/fixtures.go | 166 +++++++++++++++++++++++ 3 files changed, 359 insertions(+), 6 deletions(-) diff --git a/server/events/event_parser.go b/server/events/event_parser.go index d427a4202a..380ec3cd3f 100644 --- a/server/events/event_parser.go +++ b/server/events/event_parser.go @@ -786,6 +786,7 @@ func (e *EventParser) ParseAzureDevopsPull(pull *azuredevops.GitPullRequest) (pu err = errors.New("url is null") return } + headBranch := pull.GetSourceRefName() if headBranch == "" { err = errors.New("sourceRefName (branch name) is null") @@ -851,19 +852,22 @@ func (e *EventParser) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (m teamProject := adRepo.GetProject() parent := adRepo.GetParentRepository() owner := "" + + uri, err := url.Parse(adRepo.GetWebURL()) + if err != nil { + return models.Repo{}, err + } + if parent != nil { owner = parent.GetName() } else { - uri, err := url.Parse(adRepo.GetWebURL()) - if err != nil { - return models.Repo{}, err - } + if strings.Contains(uri.Host, "visualstudio.com") { owner = strings.Split(uri.Host, ".")[0] } else if strings.Contains(uri.Host, "dev.azure.com") { owner = strings.Split(uri.Path, "/")[1] } else { - owner = "" + owner = strings.Split(uri.Path, "/")[1] // to support owner for self hosted } } @@ -872,7 +876,14 @@ func (e *EventParser) ParseAzureDevopsRepo(adRepo *azuredevops.GitRepository) (m // https://docs.microsoft.com/en-us/azure/devops/release-notes/2018/sep-10-azure-devops-launch#switch-existing-organizations-to-use-the-new-domain-name-url project := teamProject.GetName() repo := adRepo.GetName() - cloneURL := fmt.Sprintf("https://dev.azure.com/%s/%s/_git/%s", owner, project, repo) + + host := uri.Host + if host == "" { + host = "dev.azure.com" + } + + cloneURL := fmt.Sprintf("https://%s/%s/%s/_git/%s", host, owner, project, repo) + fmt.Println("%", cloneURL) fullName := fmt.Sprintf("%s/%s/%s", owner, project, repo) return models.NewRepo(models.AzureDevops, fullName, cloneURL, e.AzureDevopsUser, e.AzureDevopsToken) } diff --git a/server/events/event_parser_test.go b/server/events/event_parser_test.go index c98fcd8ab5..47a93e5bac 100644 --- a/server/events/event_parser_test.go +++ b/server/events/event_parser_test.go @@ -1313,3 +1313,179 @@ func TestParseAzureDevopsPull(t *testing.T) { Equals(t, expBaseRepo, actBaseRepo) Equals(t, expBaseRepo, actHeadRepo) } + +func TestParseAzureDevopsSelfHostedRepo(t *testing.T) { + // this should be successful + repo := ADSelfRepo + repo.ParentRepository = nil + r, err := parser.ParseAzureDevopsRepo(&repo) + Ok(t, err) + Equals(t, models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@devops.abc.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@devops.abc.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "devops.abc.com", + Type: models.AzureDevops, + }, + }, r) + +} + +func TestParseAzureDevopsSelfHostedPullEvent(t *testing.T) { + _, _, _, _, _, err := parser.ParseAzureDevopsPullEvent(ADSelfPullEvent) + Ok(t, err) + + testPull := deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.LastMergeSourceCommit.CommitID = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "lastMergeSourceCommit.commitID is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.URL = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "url is null", err) + testEvent := deepcopy.Copy(ADSelfPullEvent).(azuredevops.Event) + resource := deepcopy.Copy(testEvent.Resource).(*azuredevops.GitPullRequest) + resource.CreatedBy = nil + testEvent.Resource = resource + _, _, _, _, _, err = parser.ParseAzureDevopsPullEvent(testEvent) + ErrEquals(t, "CreatedBy is null", err) + + testEvent = deepcopy.Copy(ADSelfPullEvent).(azuredevops.Event) + resource = deepcopy.Copy(testEvent.Resource).(*azuredevops.GitPullRequest) + resource.CreatedBy.UniqueName = azuredevops.String("") + testEvent.Resource = resource + _, _, _, _, _, err = parser.ParseAzureDevopsPullEvent(testEvent) + ErrEquals(t, "CreatedBy.UniqueName is null", err) + + actPull, evType, actBaseRepo, actHeadRepo, actUser, err := parser.ParseAzureDevopsPullEvent(ADSelfPullEvent) + Ok(t, err) + expBaseRepo := models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@devops.abc.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@devops.abc.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "devops.abc.com", + Type: models.AzureDevops, + }, + } + Equals(t, expBaseRepo, actBaseRepo) + Equals(t, expBaseRepo, actHeadRepo) + Equals(t, models.PullRequest{ + URL: ADSelfPull.GetURL(), + Author: ADSelfPull.CreatedBy.GetUniqueName(), + HeadBranch: "feature/sourceBranch", + BaseBranch: "targetBranch", + HeadCommit: ADSelfPull.LastMergeSourceCommit.GetCommitID(), + Num: ADSelfPull.GetPullRequestID(), + State: models.OpenPullState, + BaseRepo: expBaseRepo, + }, actPull) + Equals(t, models.OpenedPullEvent, evType) + Equals(t, models.User{Username: "user@example.com"}, actUser) +} + +func TestParseAzureDevopsSelfHostedPullEvent_EventType(t *testing.T) { + cases := []struct { + action string + exp models.PullRequestEventType + }{ + { + action: "git.pullrequest.updated", + exp: models.UpdatedPullEvent, + }, + { + action: "git.pullrequest.created", + exp: models.OpenedPullEvent, + }, + { + action: "git.pullrequest.updated", + exp: models.ClosedPullEvent, + }, + { + action: "anything_else", + exp: models.OtherPullEvent, + }, + } + + for _, c := range cases { + t.Run(c.action, func(t *testing.T) { + event := deepcopy.Copy(ADSelfPullEvent).(azuredevops.Event) + if c.exp == models.ClosedPullEvent { + event = deepcopy.Copy(ADSelfPullClosedEvent).(azuredevops.Event) + } + event.EventType = c.action + _, actType, _, _, _, err := parser.ParseAzureDevopsPullEvent(event) + Ok(t, err) + Equals(t, c.exp, actType) + }) + } +} + +func TestParseAzureSelfHostedDevopsPull(t *testing.T) { + testPull := deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.LastMergeSourceCommit.CommitID = nil + _, _, _, err := parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "lastMergeSourceCommit.commitID is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.URL = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "url is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.SourceRefName = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "sourceRefName (branch name) is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.TargetRefName = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "targetRefName (branch name) is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.CreatedBy = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "CreatedBy is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.CreatedBy.UniqueName = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "CreatedBy.UniqueName is null", err) + + testPull = deepcopy.Copy(ADSelfPull).(azuredevops.GitPullRequest) + testPull.PullRequestID = nil + _, _, _, err = parser.ParseAzureDevopsPull(&testPull) + ErrEquals(t, "pullRequestId is null", err) + + actPull, actBaseRepo, actHeadRepo, err := parser.ParseAzureDevopsPull(&ADSelfPull) + Ok(t, err) + expBaseRepo := models.Repo{ + Owner: "owner/project", + FullName: "owner/project/repo", + CloneURL: "https://azuredevops-user:azuredevops-token@devops.abc.com/owner/project/_git/repo", + SanitizedCloneURL: "https://azuredevops-user:@devops.abc.com/owner/project/_git/repo", + Name: "repo", + VCSHost: models.VCSHost{ + Hostname: "devops.abc.com", + Type: models.AzureDevops, + }, + } + Equals(t, models.PullRequest{ + URL: ADSelfPull.GetURL(), + Author: ADSelfPull.CreatedBy.GetUniqueName(), + HeadBranch: "feature/sourceBranch", + BaseBranch: "targetBranch", + HeadCommit: ADSelfPull.LastMergeSourceCommit.GetCommitID(), + Num: ADSelfPull.GetPullRequestID(), + State: models.OpenPullState, + BaseRepo: expBaseRepo, + }, actPull) + Equals(t, expBaseRepo, actBaseRepo) + Equals(t, expBaseRepo, actHeadRepo) +} diff --git a/server/events/vcs/fixtures/fixtures.go b/server/events/vcs/fixtures/fixtures.go index 75330cbe0c..5d02277f06 100644 --- a/server/events/vcs/fixtures/fixtures.go +++ b/server/events/vcs/fixtures/fixtures.go @@ -227,6 +227,172 @@ var ADPullJSON = `{ "artifactId": "vstfs:///Git/PullRequestId/a7573007-bbb3-4341-b726-0c4148a07853%2f3411ebc1-d5aa-464f-9615-0b527bc66719%2f22" }` +var ADSelfPullEvent = azuredevops.Event{ + EventType: "git.pullrequest.created", + Resource: &ADSelfPull, +} + +var ADSelfPullUpdatedEvent = azuredevops.Event{ + EventType: "git.pullrequest.updated", + Resource: &ADSelfPull, +} + +var ADSelfPullClosedEvent = azuredevops.Event{ + EventType: "git.pullrequest.merged", + Resource: &ADSelfPullCompleted, +} + +var ADSelfPull = azuredevops.GitPullRequest{ + CreatedBy: &azuredevops.IdentityRef{ + ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), + DisplayName: azuredevops.String("User"), + UniqueName: azuredevops.String("user@example.com"), + }, + LastMergeSourceCommit: &azuredevops.GitCommitRef{ + CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + URL: azuredevops.String("https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + }, + PullRequestID: azuredevops.Int(1), + Repository: &ADSelfRepo, + SourceRefName: azuredevops.String("refs/heads/feature/sourceBranch"), + Status: azuredevops.String("active"), + TargetRefName: azuredevops.String("refs/heads/targetBranch"), + URL: azuredevops.String("https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), +} + +var ADSelfPullCompleted = azuredevops.GitPullRequest{ + CreatedBy: &azuredevops.IdentityRef{ + ID: azuredevops.String("d6245f20-2af8-44f4-9451-8107cb2767db"), + DisplayName: azuredevops.String("User"), + UniqueName: azuredevops.String("user@example.com"), + }, + LastMergeSourceCommit: &azuredevops.GitCommitRef{ + CommitID: azuredevops.String("b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + URL: azuredevops.String("https://https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3"), + }, + PullRequestID: azuredevops.Int(1), + Repository: &ADSelfRepo, + SourceRefName: azuredevops.String("refs/heads/owner/sourceBranch"), + Status: azuredevops.String("completed"), + TargetRefName: azuredevops.String("refs/heads/targetBranch"), + URL: azuredevops.String("https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/21"), +} + +var ADSelfRepo = azuredevops.GitRepository{ + DefaultBranch: azuredevops.String("refs/heads/master"), + Name: azuredevops.String("repo"), + ParentRepository: &azuredevops.GitRepositoryRef{ + Name: azuredevops.String("owner"), + }, + Project: &azuredevops.TeamProjectReference{ + ID: azuredevops.String("a21f5f20-4a12-aaf4-ab12-9a0927cbbb90"), + Name: azuredevops.String("project"), + State: azuredevops.String("unchanged"), + }, + WebURL: azuredevops.String("https://devops.abc.com/owner/project/_git/repo"), +} + +var ADSelfPullJSON = `{ + "repository": { + "id": "3411ebc1-d5aa-464f-9615-0b527bc66719", + "name": "repo", + "url": "https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", + "webUrl": "https://devops.abc.com/owner/project/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719", + "project": { + "id": "a7573007-bbb3-4341-b726-0c4148a07853", + "name": "project", + "description": "test project created on Halloween 2016", + "url": "https://dev.azure.com/owner/_apis/projects/a7573007-bbb3-4341-b726-0c4148a07853", + "state": "wellFormed", + "revision": 7 + }, + "remoteUrl": "https://devops.abc.com/owner/project/_git/repo" + }, + "pullRequestId": 22, + "codeReviewId": 22, + "status": "active", + "createdBy": { + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "displayName": "Normal Paulk", + "uniqueName": "fabrikamfiber16@hotmail.com", + "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" + }, + "creationDate": "2016-11-01T16:30:31.6655471Z", + "title": "A new feature", + "description": "Adding a new feature", + "sourceRefName": "refs/heads/npaulk/my_work", + "targetRefName": "refs/heads/new_feature", + "mergeStatus": "succeeded", + "mergeId": "f5fc8381-3fb2-49fe-8a0d-27dcc2d6ef82", + "lastMergeSourceCommit": { + "commitId": "b60280bc6e62e2f880f1b63c1e24987664d3bda3", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" + }, + "lastMergeTargetCommit": { + "commitId": "f47bbc106853afe3c1b07a81754bce5f4b8dbf62", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" + }, + "lastMergeCommit": { + "commitId": "39f52d24533cc712fc845ed9fd1b6c06b3942588", + "author": { + "name": "Normal Paulk", + "email": "fabrikamfiber16@hotmail.com", + "date": "2016-11-01T16:30:32Z" + }, + "committer": { + "name": "Normal Paulk", + "email": "fabrikamfiber16@hotmail.com", + "date": "2016-11-01T16:30:32Z" + }, + "comment": "Merge pull request 22 from npaulk/my_work into new_feature", + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/39f52d24533cc712fc845ed9fd1b6c06b3942588" + }, + "reviewers": [ + { + "reviewerUrl": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/reviewers/d6245f20-2af8-44f4-9451-8107cb2767db", + "vote": 0, + "id": "d6245f20-2af8-44f4-9451-8107cb2767db", + "displayName": "Normal Paulk", + "uniqueName": "fabrikamfiber16@hotmail.com", + "url": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db", + "imageUrl": "https://dev.azure.com/owner/_api/_common/identityImage?id=d6245f20-2af8-44f4-9451-8107cb2767db" + } + ], + "url": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22", + "_links": { + "self": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22" + }, + "repository": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719" + }, + "workItems": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/workitems" + }, + "sourceBranch": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" + }, + "targetBranch": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/refs" + }, + "sourceCommit": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/b60280bc6e62e2f880f1b63c1e24987664d3bda3" + }, + "targetCommit": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/commits/f47bbc106853afe3c1b07a81754bce5f4b8dbf62" + }, + "createdBy": { + "href": "https://dev.azure.com/owner/_apis/Identities/d6245f20-2af8-44f4-9451-8107cb2767db" + }, + "iterations": { + "href": "https://dev.azure.com/owner/_apis/git/repositories/3411ebc1-d5aa-464f-9615-0b527bc66719/pullRequests/22/iterations" + } + }, + "supportsIterations": true, + "artifactId": "vstfs:///Git/PullRequestId/a7573007-bbb3-4341-b726-0c4148a07853%2f3411ebc1-d5aa-464f-9615-0b527bc66719%2f22" +}` + const GithubPrivateKey = `-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAuEPzOUE+kiEH1WLiMeBytTEF856j0hOVcSUSUkZxKvqczkWM 9vo1gDyC7ZXhdH9fKh32aapba3RSsp4ke+giSmYTk2mGR538ShSDxh0OgpJmjiKP From cb07e2adb034631fc42ae196178481465832f930 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Thu, 28 Oct 2021 13:46:36 -0400 Subject: [PATCH 10/20] deps: tf 1.0.10 --- .circleci/config.yml | 2 +- Dockerfile | 2 +- testdrive/utils.go | 2 +- testing/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 302f597e44..c21bb7f224 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ jobs: # We do this instead of setting --default-tf-version because setting # that flag starts the download asynchronously so we'd have a race # condition. - TERRAFORM_VERSION: 1.0.9 + TERRAFORM_VERSION: 1.0.10 steps: - checkout - run: make build-service diff --git a/Dockerfile b/Dockerfile index 484c4bedc5..9584d94610 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ghcr.io/runatlantis/atlantis-base:2021.08.31 # install terraform binaries -ENV DEFAULT_TERRAFORM_VERSION=1.0.9 +ENV DEFAULT_TERRAFORM_VERSION=1.0.10 # In the official Atlantis image we only have the latest of each Terraform version. RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.15 0.12.31 0.13.7 0.14.11 0.15.5 ${DEFAULT_TERRAFORM_VERSION}" && \ diff --git a/testdrive/utils.go b/testdrive/utils.go index 592d5f1065..3c6eabc971 100644 --- a/testdrive/utils.go +++ b/testdrive/utils.go @@ -34,7 +34,7 @@ import ( ) const hashicorpReleasesURL = "https://releases.hashicorp.com" -const terraformVersion = "1.0.9" +const terraformVersion = "1.0.10" const ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb" const ngrokAPIURL = "localhost:41414" // We hope this isn't used. const atlantisPort = 4141 diff --git a/testing/Dockerfile b/testing/Dockerfile index 9fef892cfa..323f8ba0ab 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -1,7 +1,7 @@ FROM circleci/golang:1.17 # Install Terraform -ENV TERRAFORM_VERSION=1.0.9 +ENV TERRAFORM_VERSION=1.0.10 RUN curl -LOks https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \ sudo mkdir -p /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ sudo unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ From 3dd4940a153727067c42e1913699d56606f87923 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Oct 2021 13:48:21 -0400 Subject: [PATCH 11/20] build(deps): bump github.com/microcosm-cc/bluemonday (#1868) Bumps [github.com/microcosm-cc/bluemonday](https://github.com/microcosm-cc/bluemonday) from 1.0.15 to 1.0.16. - [Release notes](https://github.com/microcosm-cc/bluemonday/releases) - [Commits](https://github.com/microcosm-cc/bluemonday/compare/v1.0.15...v1.0.16) --- updated-dependencies: - dependency-name: github.com/microcosm-cc/bluemonday dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 ++- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e716c30324..16f473b4b9 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-isatty v0.0.12 // indirect github.com/mcdafydd/go-azuredevops v0.12.1 - github.com/microcosm-cc/bluemonday v1.0.15 + github.com/microcosm-cc/bluemonday v1.0.16 github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 @@ -120,6 +120,7 @@ require ( ) require ( + github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect github.com/google/go-github/v39 v39.1.0 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect ) diff --git a/go.sum b/go.sum index 5185676f3c..df9a10661f 100644 --- a/go.sum +++ b/go.sum @@ -316,8 +316,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mcdafydd/go-azuredevops v0.12.1 h1:WxwLVyGuJ8oL7uWQp1/J6GefX1wMQQZUHWRGsrm+uE8= github.com/mcdafydd/go-azuredevops v0.12.1/go.mod h1:B4UDyn7WEj1/97f45j3VnzEfkWKe05+/dCcAPdOET4A= -github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY= -github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= +github.com/microcosm-cc/bluemonday v1.0.16 h1:kHmAq2t7WPWLjiGvzKa5o3HzSfahUKiOq7fAPUiMNIc= +github.com/microcosm-cc/bluemonday v1.0.16/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= From 720d8eb2d4e3607ae73f7110a002d43ce104fb04 Mon Sep 17 00:00:00 2001 From: rui Date: Thu, 28 Oct 2021 14:04:53 -0400 Subject: [PATCH 12/20] deps: conftest 0.28.2 (#1872) --- Dockerfile | 2 +- Dockerfile.dev | 2 +- testing/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9584d94610..b22b107b23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.15 0.12.31 0.13.7 0.1 done && \ ln -s /usr/local/bin/tf/versions/${DEFAULT_TERRAFORM_VERSION}/terraform /usr/local/bin/terraform -ENV DEFAULT_CONFTEST_VERSION=0.28.1 +ENV DEFAULT_CONFTEST_VERSION=0.28.2 RUN AVAILABLE_CONFTEST_VERSIONS="${DEFAULT_CONFTEST_VERSION}" && \ for VERSION in ${AVAILABLE_CONFTEST_VERSIONS}; do \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 19217625af..f1e1cff3c1 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,6 +1,6 @@ FROM ghcr.io/runatlantis/atlantis:latest COPY atlantis /usr/local/bin/atlantis # TODO: remove this once we get this in the base image -ENV DEFAULT_CONFTEST_VERSION=0.28.1 +ENV DEFAULT_CONFTEST_VERSION=0.28.2 WORKDIR /atlantis/src diff --git a/testing/Dockerfile b/testing/Dockerfile index 323f8ba0ab..5b132b1de8 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -9,7 +9,7 @@ RUN curl -LOks https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/ter rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip # Install conftest -ENV CONFTEST_VERSION=0.28.1 +ENV CONFTEST_VERSION=0.28.2 RUN curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz && \ curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/checksums.txt && \ sed -n "/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz/p" checksums.txt | sha256sum -c && \ From 8c9184b80af8b35ca891e526ede411bf447c3a86 Mon Sep 17 00:00:00 2001 From: Mihail Kuzmich <32264674+kuzm1ch@users.noreply.github.com> Date: Thu, 28 Oct 2021 21:50:05 +0300 Subject: [PATCH 13/20] feat: add new bitbucket server webhook event type pr:from_ref_updated (#1866) --- server/controllers/events/events_controller.go | 2 +- server/events/event_parser.go | 4 +++- server/events/vcs/bitbucketserver/models.go | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/controllers/events/events_controller.go b/server/controllers/events/events_controller.go index c94f2d648c..cd4d097aeb 100644 --- a/server/controllers/events/events_controller.go +++ b/server/controllers/events/events_controller.go @@ -205,7 +205,7 @@ func (e *VCSEventsController) handleBitbucketServerPost(w http.ResponseWriter, r } } switch eventType { - case bitbucketserver.PullCreatedHeader, bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: + case bitbucketserver.PullCreatedHeader, bitbucketserver.PullFromRefUpdatedHeader, bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: e.Logger.Debug("handling as pull request state changed event") e.handleBitbucketServerPullRequestEvent(w, eventType, body, reqID) return diff --git a/server/events/event_parser.go b/server/events/event_parser.go index 380ec3cd3f..0f487d17dd 100644 --- a/server/events/event_parser.go +++ b/server/events/event_parser.go @@ -636,7 +636,9 @@ func (e *EventParser) ParseGitlabMergeRequest(mr *gitlab.MergeRequest, baseRepo // event given the Bitbucket Server header. func (e *EventParser) GetBitbucketServerPullEventType(eventTypeHeader string) models.PullRequestEventType { switch eventTypeHeader { - case bitbucketserver.PullCreatedHeader: + // PullFromRefUpdatedHeader event occurs on OPEN state pull request + // so no additional checks are needed. + case bitbucketserver.PullCreatedHeader, bitbucketserver.PullFromRefUpdatedHeader: return models.OpenedPullEvent case bitbucketserver.PullMergedHeader, bitbucketserver.PullDeclinedHeader, bitbucketserver.PullDeletedHeader: return models.ClosedPullEvent diff --git a/server/events/vcs/bitbucketserver/models.go b/server/events/vcs/bitbucketserver/models.go index f9c34d4fc9..5646ca4256 100644 --- a/server/events/vcs/bitbucketserver/models.go +++ b/server/events/vcs/bitbucketserver/models.go @@ -3,6 +3,7 @@ package bitbucketserver const ( DiagnosticsPingHeader = "diagnostics:ping" PullCreatedHeader = "pr:opened" + PullFromRefUpdatedHeader = "pr:from_ref_updated" PullMergedHeader = "pr:merged" PullDeclinedHeader = "pr:declined" PullDeletedHeader = "pr:deleted" From 2a0b78051e697735f92d4b36d8f1b3aeea1aec03 Mon Sep 17 00:00:00 2001 From: rui Date: Sun, 31 Oct 2021 11:38:49 -0400 Subject: [PATCH 14/20] feat: use goreleaser to replace the binary-release script (#1873) * feat: add goreleaser flow * del binary-release script --- .github/workflows/release.yml | 26 ++++++++++++++++++ .gitignore | 5 +++- .goreleaser.yml | 34 ++++++++++++++++++++++++ scripts/binary-release.sh | 50 ----------------------------------- 4 files changed, 64 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .goreleaser.yml delete mode 100755 scripts/binary-release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..599f57a336 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,26 @@ +name: release + +on: + push: + tags: + - v*.*.* + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: v0.183.0 + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index a9ca864199..fd0a0c95ac 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,7 @@ helm/test-values.yaml *.swp golangci-lint atlantis -.devcontainer \ No newline at end of file +.devcontainer + +# gitreleaser +dist/ diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000000..248d424d80 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,34 @@ +env: + - CGO_ENABLED=0 +builds: + - targets: + - darwin_amd64 + - darwin_arm64 + - linux_386 + - linux_amd64 + - linux_arm + - linux_arm64 + - windows_386 + - windows_amd64 + +archives: + - id: zip + name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" + format: zip + files: + - none* + +checksum: + name_template: 'checksums.txt' + +changelog: + skip: true + +release: + github: + owner: runatlantis + name: atlantis + draft: true + +snapshot: + name_template: "{{ incpatch .Version }}-next" diff --git a/scripts/binary-release.sh b/scripts/binary-release.sh deleted file mode 100755 index ffbf4c229d..0000000000 --- a/scripts/binary-release.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# define architecture we want to build -XC_ARCH=${XC_ARCH:-"386 amd64 arm arm64"} -XC_OS=${XC_OS:-linux darwin} -XC_EXCLUDE_OSARCH="!darwin/arm !darwin/386 !darwin/arm64" - -# clean up -echo "-> running clean up...." -rm -rf output/* - -if ! which gox > /dev/null; then - echo "-> installing gox..." - # Need to run go get in a separate dir - # so it doesn't modify our go.mod. - SRC_DIR=$(pwd) - cd $(mktemp -d) - go mod init example.com/m - go get -u github.com/mitchellh/gox - cd "$SRC_DIR" -fi - -# build -# we want to build statically linked binaries -export CGO_ENABLED=0 -echo "-> building..." -gox \ - -os="${XC_OS}" \ - -arch="${XC_ARCH}" \ - -osarch="${XC_EXCLUDE_OSARCH}" \ - -output "output/{{.OS}}_{{.Arch}}/atlantis" \ - . - -# Zip and copy to the dist dir -echo "" -echo "Packaging..." -for PLATFORM in $(find ./output -mindepth 1 -maxdepth 1 -type d); do - OSARCH=$(basename ${PLATFORM}) - echo "--> ${OSARCH}" - - pushd $PLATFORM >/dev/null 2>&1 - zip ../atlantis_${OSARCH}.zip ./* - popd >/dev/null 2>&1 -done - -echo "" -echo "" -echo "-----------------------------------" -echo "Output:" -ls -alh output/ From a8bfd77452a7e5b2298e1c94ed23b2b2c56fa31c Mon Sep 17 00:00:00 2001 From: Nish Krishnan Date: Mon, 1 Nov 2021 11:32:52 -0700 Subject: [PATCH 15/20] Move runtime common under existing runtime package. (#1875) --- server/{events => core}/runtime/common/common.go | 0 server/{events => core}/runtime/common/common_test.go | 0 server/core/runtime/init_step_runner.go | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename server/{events => core}/runtime/common/common.go (100%) rename server/{events => core}/runtime/common/common_test.go (100%) diff --git a/server/events/runtime/common/common.go b/server/core/runtime/common/common.go similarity index 100% rename from server/events/runtime/common/common.go rename to server/core/runtime/common/common.go diff --git a/server/events/runtime/common/common_test.go b/server/core/runtime/common/common_test.go similarity index 100% rename from server/events/runtime/common/common_test.go rename to server/core/runtime/common/common_test.go diff --git a/server/core/runtime/init_step_runner.go b/server/core/runtime/init_step_runner.go index 77e1daad47..c1f5438e66 100644 --- a/server/core/runtime/init_step_runner.go +++ b/server/core/runtime/init_step_runner.go @@ -5,8 +5,8 @@ import ( "path/filepath" version "github.com/hashicorp/go-version" + "github.com/runatlantis/atlantis/server/core/runtime/common" "github.com/runatlantis/atlantis/server/events/models" - "github.com/runatlantis/atlantis/server/events/runtime/common" ) // InitStep runs `terraform init`. From ac9a6c3c4fea5941fcb241c0ee9a55ef8403be3a Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Wed, 3 Nov 2021 22:34:39 -0400 Subject: [PATCH 16/20] deps: conftest 0.28.3 Signed-off-by: Rui Chen --- Dockerfile | 2 +- Dockerfile.dev | 2 +- testing/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b22b107b23..e836818c2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.15 0.12.31 0.13.7 0.1 done && \ ln -s /usr/local/bin/tf/versions/${DEFAULT_TERRAFORM_VERSION}/terraform /usr/local/bin/terraform -ENV DEFAULT_CONFTEST_VERSION=0.28.2 +ENV DEFAULT_CONFTEST_VERSION=0.28.3 RUN AVAILABLE_CONFTEST_VERSIONS="${DEFAULT_CONFTEST_VERSION}" && \ for VERSION in ${AVAILABLE_CONFTEST_VERSIONS}; do \ diff --git a/Dockerfile.dev b/Dockerfile.dev index f1e1cff3c1..607274679e 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,6 +1,6 @@ FROM ghcr.io/runatlantis/atlantis:latest COPY atlantis /usr/local/bin/atlantis # TODO: remove this once we get this in the base image -ENV DEFAULT_CONFTEST_VERSION=0.28.2 +ENV DEFAULT_CONFTEST_VERSION=0.28.3 WORKDIR /atlantis/src diff --git a/testing/Dockerfile b/testing/Dockerfile index 5b132b1de8..3ee5147a9a 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -9,7 +9,7 @@ RUN curl -LOks https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/ter rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip # Install conftest -ENV CONFTEST_VERSION=0.28.2 +ENV CONFTEST_VERSION=0.28.3 RUN curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz && \ curl -LOs https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/checksums.txt && \ sed -n "/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz/p" checksums.txt | sha256sum -c && \ From f4314e2f12bffebe5bc0788c1d3907ab4452f6cc Mon Sep 17 00:00:00 2001 From: rui Date: Thu, 4 Nov 2021 19:48:13 -0400 Subject: [PATCH 17/20] release: 0.17.5 (#1874) * release: 0.17.5 Signed-off-by: Rui Chen * update changelog Signed-off-by: Rui Chen --- CHANGELOG.md | 14 ++++++++++++++ kustomize/bundle.yaml | 2 +- main.go | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7af0b016f4..8f2c12954f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# v0.17.5 + +## What's Changed + +* refactor: move from io/ioutil to io and os package by @Juneezee in https://github.com/runatlantis/atlantis/pull/1843 +* chore: use golang-jwt/jwt to replace dgrijalva/jwt-go by @barn in https://github.com/runatlantis/atlantis/pull/1845 +* fix(azure): allow host to be specified in user_config for on premise installation by @dandcg in https://github.com/runatlantis/atlantis/pull/1860 +* feat: filter out atlantis/apply from mergeability clause by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1856 +* feat: add BasicAuth Support to Atlantis ServeHTTP by @fblgit in https://github.com/runatlantis/atlantis/pull/1777 +* fix(azure): allow correct path to be derived for on premise installation by @dandcg in https://github.com/runatlantis/atlantis/pull/1863 +* feat: add new bitbucket server webhook event type pr:from_ref_updated(#198) by @kuzm1ch in https://github.com/runatlantis/atlantis/pull/1866 +* Move runtime common under existing runtime package. by @nishkrishnan in https://github.com/runatlantis/atlantis/pull/1875 +* feat: use goreleaser to replace the binary-release script by @chenrui333 in https://github.com/runatlantis/atlantis/pull/1873 + # v0.17.4 ## What's Changed diff --git a/kustomize/bundle.yaml b/kustomize/bundle.yaml index d99004eb7c..dd9efb46cc 100644 --- a/kustomize/bundle.yaml +++ b/kustomize/bundle.yaml @@ -22,7 +22,7 @@ spec: fsGroup: 1000 # Atlantis group (1000) read/write access to volumes. containers: - name: atlantis - image: ghcr.io/runatlantis/atlantis:v0.17.4 + image: ghcr.io/runatlantis/atlantis:v0.17.5 env: - name: ATLANTIS_DATA_DIR value: /atlantis diff --git a/main.go b/main.go index 041d9c21d9..0725176a3b 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ import ( "github.com/spf13/viper" ) -const atlantisVersion = "0.17.4" +const atlantisVersion = "0.17.5" func main() { v := viper.New() From 6d86119d7578b0f1ae2ae309cc3c4c1b4a51ea52 Mon Sep 17 00:00:00 2001 From: rui Date: Wed, 10 Nov 2021 18:44:50 -0500 Subject: [PATCH 18/20] deps: tf 1.0.11 (#1892) --- .circleci/config.yml | 2 +- Dockerfile | 2 +- testdrive/utils.go | 2 +- testing/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c21bb7f224..b3794a2c6c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ jobs: # We do this instead of setting --default-tf-version because setting # that flag starts the download asynchronously so we'd have a race # condition. - TERRAFORM_VERSION: 1.0.10 + TERRAFORM_VERSION: 1.0.11 steps: - checkout - run: make build-service diff --git a/Dockerfile b/Dockerfile index e836818c2c..d3f22f3250 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ghcr.io/runatlantis/atlantis-base:2021.08.31 # install terraform binaries -ENV DEFAULT_TERRAFORM_VERSION=1.0.10 +ENV DEFAULT_TERRAFORM_VERSION=1.0.11 # In the official Atlantis image we only have the latest of each Terraform version. RUN AVAILABLE_TERRAFORM_VERSIONS="0.8.8 0.9.11 0.10.8 0.11.15 0.12.31 0.13.7 0.14.11 0.15.5 ${DEFAULT_TERRAFORM_VERSION}" && \ diff --git a/testdrive/utils.go b/testdrive/utils.go index 3c6eabc971..ed31ad0a44 100644 --- a/testdrive/utils.go +++ b/testdrive/utils.go @@ -34,7 +34,7 @@ import ( ) const hashicorpReleasesURL = "https://releases.hashicorp.com" -const terraformVersion = "1.0.10" +const terraformVersion = "1.0.11" const ngrokDownloadURL = "https://bin.equinox.io/c/4VmDzA7iaHb" const ngrokAPIURL = "localhost:41414" // We hope this isn't used. const atlantisPort = 4141 diff --git a/testing/Dockerfile b/testing/Dockerfile index 3ee5147a9a..1087f11a7b 100644 --- a/testing/Dockerfile +++ b/testing/Dockerfile @@ -1,7 +1,7 @@ FROM circleci/golang:1.17 # Install Terraform -ENV TERRAFORM_VERSION=1.0.10 +ENV TERRAFORM_VERSION=1.0.11 RUN curl -LOks https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \ sudo mkdir -p /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ sudo unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/local/bin/tf/versions/${TERRAFORM_VERSION} && \ From d310e2f17015a0a41483ab9584c5291bc67a93f5 Mon Sep 17 00:00:00 2001 From: Tom Harrison Date: Fri, 12 Nov 2021 14:36:24 -0500 Subject: [PATCH 19/20] docs: clarify maximum version limit (#1894) * Clarify maximum version limit When latest Docker image still had terraform 1.0.0, for example, any method of specifying a higher version failed to build. This note clarifies the dependency. * update the docker image reference Co-authored-by: rui --- runatlantis.io/docs/terraform-versions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runatlantis.io/docs/terraform-versions.md b/runatlantis.io/docs/terraform-versions.md index 36dae57d33..7b946c792c 100644 --- a/runatlantis.io/docs/terraform-versions.md +++ b/runatlantis.io/docs/terraform-versions.md @@ -27,3 +27,7 @@ See [Terraform `required_version`](https://www.terraform.io/docs/configuration/t Atlantis will automatically download the version specified. ::: +::: tip NOTE +The Atlantis [latest docker image](https://github.com/runatlantis/atlantis/pkgs/container/atlantis/9854680?tag=latest) tends to have recent versions of Terraform, but there may be a delay as new versions are released. The highest version of Terraform allowed in your code is the version specified by `DEFAULT_TERRAFORM_VERSION` in the image your server is running. +::: + From 24001aa8303619042bf9939777ff5e9be7246de8 Mon Sep 17 00:00:00 2001 From: rui Date: Fri, 12 Nov 2021 15:18:05 -0500 Subject: [PATCH 20/20] docs: revert to use docker hub page as 404 on github pkg registry (#1897) Signed-off-by: Rui Chen --- runatlantis.io/docs/terraform-versions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runatlantis.io/docs/terraform-versions.md b/runatlantis.io/docs/terraform-versions.md index 7b946c792c..02351dc9d4 100644 --- a/runatlantis.io/docs/terraform-versions.md +++ b/runatlantis.io/docs/terraform-versions.md @@ -28,6 +28,5 @@ Atlantis will automatically download the version specified. ::: ::: tip NOTE -The Atlantis [latest docker image](https://github.com/runatlantis/atlantis/pkgs/container/atlantis/9854680?tag=latest) tends to have recent versions of Terraform, but there may be a delay as new versions are released. The highest version of Terraform allowed in your code is the version specified by `DEFAULT_TERRAFORM_VERSION` in the image your server is running. +The Atlantis [latest docker image](https://hub.docker.com/layers/runatlantis/atlantis/latest/images/sha256-4f80472e20bd899b03a619e593f9e7b9a55d9e630850de443b988295f63f5c7a?context=explore) tends to have recent versions of Terraform, but there may be a delay as new versions are released. The highest version of Terraform allowed in your code is the version specified by `DEFAULT_TERRAFORM_VERSION` in the image your server is running. ::: -