From 3f5b95a2343e0b35b8a9157b2a9ab0befbb13634 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 11 Dec 2020 00:22:28 -0800 Subject: [PATCH 1/5] Removes GitHub OAuth token hashing --- aws/resource_aws_codepipeline.go | 93 ++++++++++----------------- aws/resource_aws_codepipeline_test.go | 4 +- go.mod | 1 + website/docs/r/codepipeline.markdown | 2 +- 4 files changed, 39 insertions(+), 61 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 5cbaadce2d5..8d7821fab9b 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -1,15 +1,14 @@ package aws import ( - "crypto/sha256" - "encoding/hex" "errors" "fmt" "log" - "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -59,11 +58,9 @@ func resourceAwsCodePipeline() *schema.Resource { Required: true, }, "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.ArtifactStoreTypeS3, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(codepipeline.ArtifactStoreType_Values(), false), }, "encryption_key": { Type: schema.TypeList, @@ -76,11 +73,9 @@ func resourceAwsCodePipeline() *schema.Resource { Required: true, }, "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.EncryptionKeyTypeKms, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(codepipeline.EncryptionKeyType_Values(), false), }, }, }, @@ -109,35 +104,24 @@ func resourceAwsCodePipeline() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "configuration": { - Type: schema.TypeMap, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - DiffSuppressFunc: suppressCodePipelineStageActionConfiguration, + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, "category": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.ActionCategorySource, - codepipeline.ActionCategoryBuild, - codepipeline.ActionCategoryDeploy, - codepipeline.ActionCategoryTest, - codepipeline.ActionCategoryInvoke, - codepipeline.ActionCategoryApproval, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(codepipeline.ActionCategory_Values(), false), }, "owner": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - codepipeline.ActionOwnerAws, - codepipeline.ActionOwnerThirdParty, - codepipeline.ActionOwnerCustom, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(codepipeline.ActionOwner_Values(), false), }, "provider": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: resourceAwsCodePipelineValidateActionProvider, }, "version": { Type: schema.TypeString, @@ -425,8 +409,7 @@ func flattenAwsCodePipelineStageActions(si int, actions []*codepipeline.ActionDe if _, ok := config[CodePipelineGitHubActionConfigurationOAuthToken]; ok { // The AWS API returns "****" for the OAuthToken value. Pull the value from the configuration. addr := fmt.Sprintf("stage.%d.action.%d.configuration.OAuthToken", si, ai) - hash := hashCodePipelineGitHubToken(d.Get(addr).(string)) - config[CodePipelineGitHubActionConfigurationOAuthToken] = hash + config[CodePipelineGitHubActionConfigurationOAuthToken] = d.Get(addr).(string) } } @@ -620,27 +603,21 @@ func resourceAwsCodePipelineDelete(d *schema.ResourceData, meta interface{}) err return err } -func suppressCodePipelineStageActionConfiguration(k, old, new string, d *schema.ResourceData) bool { - parts := strings.Split(k, ".") - parts = parts[:len(parts)-2] - providerAddr := strings.Join(append(parts, "provider"), ".") - provider := d.Get(providerAddr).(string) - - if provider == CodePipelineProviderGitHub && strings.HasSuffix(k, CodePipelineGitHubActionConfigurationOAuthToken) { - hash := hashCodePipelineGitHubToken(new) - return old == hash +func resourceAwsCodePipelineValidateActionProvider(i interface{}, path cty.Path) diag.Diagnostics { + v, ok := i.(string) + if !ok { + return diag.Errorf("expected type to be string") } - return false -} - -const codePipelineGitHubTokenHashPrefix = "hash-" - -func hashCodePipelineGitHubToken(token string) string { - // Without this check, the value was getting encoded twice - if strings.HasPrefix(token, codePipelineGitHubTokenHashPrefix) { - return token + if v == CodePipelineProviderGitHub { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: "The CodePipeline GitHub version 1 action provider is deprecated.", + Detail: "Use a CodeStarSourceConnection instead.", + }, + } } - sum := sha256.Sum256([]byte(token)) - return codePipelineGitHubTokenHashPrefix + hex.EncodeToString(sum[:]) + + return nil } diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index bba8e411ebf..26d586b9f13 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -50,7 +50,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "lifesum-terraform"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "master"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", hashCodePipelineGitHubToken(githubToken)), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.role_arn", ""), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.run_order", "1"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.region", ""), @@ -98,7 +98,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "test-terraform"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test-repo"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "stable"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", hashCodePipelineGitHubToken(githubToken)), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), diff --git a/go.mod b/go.mod index 597534f085f..cf668d87d9e 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.0 github.com/hashicorp/go-cleanhttp v0.5.1 + github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-hclog v0.10.0 // indirect github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-version v1.2.1 diff --git a/website/docs/r/codepipeline.markdown b/website/docs/r/codepipeline.markdown index aa602954d0c..301aa0e4576 100644 --- a/website/docs/r/codepipeline.markdown +++ b/website/docs/r/codepipeline.markdown @@ -183,7 +183,7 @@ An `action` block supports the following arguments: * `category` - (Required) A category defines what kind of action can be taken in the stage, and constrains the provider type for the action. Possible values are `Approval`, `Build`, `Deploy`, `Invoke`, `Source` and `Test`. * `owner` - (Required) The creator of the action being called. Possible values are `AWS`, `Custom` and `ThirdParty`. * `name` - (Required) The action declaration's name. -* `provider` - (Required) The provider of the service being called by the action. Valid providers are determined by the action category. For example, an action in the Deploy category type might have a provider of AWS CodeDeploy, which would be specified as CodeDeploy. +* `provider` - (Required) The provider of the service being called by the action. Valid providers are determined by the action category. Provider names are listed in the [Action Structure Reference](https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference.html) documentation. * `version` - (Required) A string that identifies the action type. * `configuration` - (Optional) A map of the action declaration's configuration. Configurations options for action types and providers can be found in the [Pipeline Structure Reference](http://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#action-requirements) and [Action Structure Reference](https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference.html) documentation. * `input_artifacts` - (Optional) A list of artifact names to be worked on. From d0793c2539fe478f1016aa522840815353072421 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Dec 2020 18:37:39 -0800 Subject: [PATCH 2/5] Adds acceptance test for CodePipeline using CodeStar Connection source ation --- aws/resource_aws_codepipeline.go | 2 +- aws/resource_aws_codepipeline_test.go | 120 +++++++++++++++++- website/docs/r/codepipeline.markdown | 16 ++- .../r/codestarconnections_connection.markdown | 7 +- 4 files changed, 127 insertions(+), 18 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 8d7821fab9b..b66de0d158d 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -614,7 +614,7 @@ func resourceAwsCodePipelineValidateActionProvider(i interface{}, path cty.Path) diag.Diagnostic{ Severity: diag.Warning, Summary: "The CodePipeline GitHub version 1 action provider is deprecated.", - Detail: "Use a CodeStarSourceConnection instead.", + Detail: "Use a GitHub version 2 action (with a CodeStar Connection `aws_codestarconnections_connection`) instead. See https://docs.aws.amazon.com/codepipeline/latest/userguide/update-github-action-connections.html", }, } } diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 26d586b9f13..c58d4182df6 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/aws/aws-sdk-go/service/codestarconnections" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -49,7 +50,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "4"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "lifesum-terraform"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "master"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "main"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.role_arn", ""), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.run_order", "1"), @@ -493,6 +494,48 @@ func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { }) } +func TestAccAWSCodePipeline_WithCodeStarConnection(t *testing.T) { + var v codepipeline.PipelineDeclaration + name := acctest.RandString(10) + resourceName := "aws_codepipeline.test" + codestarConnectionResourceName := "aws_codestarconnections_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPartitionHasServicePreCheck(codepipeline.EndpointsID, t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCodePipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCodePipelineConfigWithCodeStarConnection(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &v), + + resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), + + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.category", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "AWS"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "CodeStarSourceConnection"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.version", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.FullRepositoryId", "lifesum-terraform/test"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.BranchName", "main"), + resource.TestCheckResourceAttrPair(resourceName, "stage.0.action.0.configuration.ConnectionArn", codestarConnectionResourceName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSCodePipelineExists(n string, pipeline *codepipeline.PipelineDeclaration) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -724,7 +767,7 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "main" OAuthToken = %[2]q } } @@ -838,7 +881,7 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "main" OAuthToken = %[2]q } } @@ -1031,7 +1074,7 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "main" OAuthToken = %[4]q } } @@ -1112,7 +1155,7 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "main" OAuthToken = %[4]q } } @@ -1202,7 +1245,7 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "main" OAuthToken = %[4]q } } @@ -1307,7 +1350,7 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "main" OAuthToken = %[2]q } } @@ -1338,6 +1381,69 @@ resource "aws_s3_bucket" "foo" { `, rName, githubToken)) } +func testAccAWSCodePipelineConfigWithCodeStarConnection(rName string) string { + return composeConfig( + testAccAWSCodePipelineS3DefaultBucket(rName), + testAccAWSCodePipelineServiceIAMRole(rName), + fmt.Sprintf(` +resource "aws_codepipeline" "test" { + name = "test-pipeline-%[1]s" + role_arn = aws_iam_role.codepipeline_role.arn + + artifact_store { + location = aws_s3_bucket.test.bucket + type = "S3" + + encryption_key { + id = "1234" + type = "KMS" + } + } + + stage { + name = "Source" + + action { + name = "Source" + category = "Source" + owner = "AWS" + provider = "CodeStarSourceConnection" + version = "1" + output_artifacts = ["test"] + + configuration = { + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" + } + } + } + + stage { + name = "Build" + + action { + name = "Build" + category = "Build" + owner = "AWS" + provider = "CodeBuild" + input_artifacts = ["test"] + version = "1" + + configuration = { + ProjectName = "test" + } + } + } +} + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName)) +} + func TestResourceAWSCodePipelineExpandArtifactStoresValidation(t *testing.T) { cases := []struct { Name string diff --git a/website/docs/r/codepipeline.markdown b/website/docs/r/codepipeline.markdown index 301aa0e4576..33ee75b2aa2 100644 --- a/website/docs/r/codepipeline.markdown +++ b/website/docs/r/codepipeline.markdown @@ -33,16 +33,15 @@ resource "aws_codepipeline" "codepipeline" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["source_output"] configuration = { - Owner = "my-organization" - Repo = "test" - Branch = "master" - OAuthToken = var.github_token + ConnectionArn = aws_codestarconnections_connection.example.arn + FullRepositoryId = "my-organization/example" + BranchName = "main" } } } @@ -87,6 +86,11 @@ resource "aws_codepipeline" "codepipeline" { } } +resource "aws_codestarconnections_connection" "example" { + name = "example-connection" + provider_type = "GitHub" +} + resource "aws_s3_bucket" "codepipeline_bucket" { bucket = "test-bucket" acl = "private" diff --git a/website/docs/r/codestarconnections_connection.markdown b/website/docs/r/codestarconnections_connection.markdown index 5aadbb83228..7b9d7b1d01a 100644 --- a/website/docs/r/codestarconnections_connection.markdown +++ b/website/docs/r/codestarconnections_connection.markdown @@ -38,10 +38,9 @@ resource "aws_codepipeline" "example" { version = "1" output_artifacts = ["source_output"] configuration = { - Owner = "my-organization" - ConnectionArn = aws_codestarconnections_connection.example.arn - Repo = "foo/test" - Branch = "master" + ConnectionArn = aws_codestarconnections_connection.example.arn + FullRepositoryId = "my-organization/test" + BranchName = "main" } } } From 7824d0b91b67c4075df2dab86b7023e9af5543dd Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Dec 2020 10:04:51 -0800 Subject: [PATCH 3/5] Separates GITHUB_TOKEN preCheck from CodePipeline service support preChek --- aws/provider_test.go | 6 +++ aws/resource_aws_codepipeline_test.go | 53 +++++++++++++------ aws/resource_aws_codepipeline_webhook_test.go | 30 +++++++++-- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index 8cbab7ba700..b90be7d7c9f 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -779,6 +779,12 @@ func testAccPreCheckIamServiceLinkedRole(t *testing.T, pathPrefix string) { } } +func testAccEnvironmentVariableSetPreCheck(variable string, t *testing.T) { + if os.Getenv(variable) == "" { + t.Skipf("skipping tests; environment variable %s must be set", variable) + } +} + func testAccAlternateAccountProviderConfig() string { //lintignore:AT004 return fmt.Sprintf(` diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index c58d4182df6..c213ffe45ce 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -23,7 +23,11 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resourceName := "aws_codepipeline.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -131,7 +135,11 @@ func TestAccAWSCodePipeline_disappears(t *testing.T) { resourceName := "aws_codepipeline.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -155,7 +163,11 @@ func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { resourceName := "aws_codepipeline.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -198,7 +210,11 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { resourceName := "aws_codepipeline.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -232,7 +248,11 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { resourceName := "aws_codepipeline.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -298,7 +318,8 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t) testAccMultipleRegionPreCheck(t, 2) - testAccPreCheckAWSCodePipeline(t, testAccGetAlternateRegion()) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t, testAccGetAlternateRegion()) }, ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -344,7 +365,8 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { PreCheck: func() { testAccPreCheck(t) testAccMultipleRegionPreCheck(t, 2) - testAccPreCheckAWSCodePipeline(t, testAccGetAlternateRegion()) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t, testAccGetAlternateRegion()) }, ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -404,7 +426,8 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { PreCheck: func() { testAccPreCheck(t) testAccMultipleRegionPreCheck(t, 2) - testAccPreCheckAWSCodePipeline(t, testAccGetAlternateRegion()) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t, testAccGetAlternateRegion()) }, ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -469,7 +492,11 @@ func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { resourceName := "aws_codepipeline.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -503,7 +530,7 @@ func TestAccAWSCodePipeline_WithCodeStarConnection(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccPartitionHasServicePreCheck(codepipeline.EndpointsID, t) + testAccPreCheckAWSCodePipelineSupported(t) testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, @@ -586,11 +613,7 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { return nil } -func testAccPreCheckAWSCodePipeline(t *testing.T, regions ...string) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - +func testAccPreCheckAWSCodePipelineSupported(t *testing.T, regions ...string) { regions = append(regions, testAccGetRegion()) for _, region := range regions { conf := &Config{ diff --git a/aws/resource_aws_codepipeline_webhook_test.go b/aws/resource_aws_codepipeline_webhook_test.go index 64673fbb2ad..cf13fdc8900 100644 --- a/aws/resource_aws_codepipeline_webhook_test.go +++ b/aws/resource_aws_codepipeline_webhook_test.go @@ -20,7 +20,11 @@ func TestAccAWSCodePipelineWebhook_basic(t *testing.T) { resourceName := "aws_codepipeline_webhook.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -51,7 +55,11 @@ func TestAccAWSCodePipelineWebhook_ipAuth(t *testing.T) { resourceName := "aws_codepipeline_webhook.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -82,7 +90,11 @@ func TestAccAWSCodePipelineWebhook_unauthenticated(t *testing.T) { resourceName := "aws_codepipeline_webhook.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -111,7 +123,11 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { resourceName := "aws_codepipeline_webhook.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ @@ -171,7 +187,11 @@ func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken resourceName := "aws_codepipeline_webhook.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) + testAccPreCheckAWSCodePipelineSupported(t) + }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ From a3bcc7e5f30a920d384e1065c8e1d0a34208f07c Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Dec 2020 19:26:12 -0800 Subject: [PATCH 4/5] Makes CodeStar Connection default for CodePipeline tests. GITHUB_TOKEN is no longer needs for most acceptance tests --- aws/resource_aws_codepipeline_test.go | 423 +++++++++++++++----------- 1 file changed, 244 insertions(+), 179 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index c213ffe45ce..b485e8effe5 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -16,23 +16,22 @@ import ( ) func TestAccAWSCodePipeline_basic(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p1, p2 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" + codestarConnectionResourceName := "aws_codestarconnections_connection.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_basic(name, githubToken), + Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttrPair(resourceName, "role_arn", "aws_iam_role.codepipeline_role", "arn"), @@ -45,17 +44,16 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.category", "Source"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "ThirdParty"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "GitHub"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "AWS"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "CodeStarSourceConnection"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.version", "1"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.input_artifacts.#", "0"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.#", "1"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.0", "test"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "4"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "lifesum-terraform"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "main"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.FullRepositoryId", "lifesum-terraform/test"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.BranchName", "main"), + resource.TestCheckResourceAttrPair(resourceName, "stage.0.action.0.configuration.ConnectionArn", codestarConnectionResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.role_arn", ""), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.run_order", "1"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.region", ""), @@ -81,13 +79,9 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, { - Config: testAccAWSCodePipelineConfig_basicUpdated(name, githubToken), + Config: testAccAWSCodePipelineConfig_basicUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), @@ -99,11 +93,10 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.input_artifacts.#", "0"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.#", "1"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.output_artifacts.0", "artifacts"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "4"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "test-terraform"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test-repo"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "stable"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.FullRepositoryId", "test-terraform/test-repo"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.BranchName", "stable"), + resource.TestCheckResourceAttrPair(resourceName, "stage.0.action.0.configuration.ConnectionArn", codestarConnectionResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), @@ -128,8 +121,6 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { } func TestAccAWSCodePipeline_disappears(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -137,14 +128,14 @@ func TestAccAWSCodePipeline_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_basic(name, githubToken), + Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), testAccCheckResourceDisappears(testAccProvider, resourceAwsCodePipeline(), resourceName), @@ -156,8 +147,6 @@ func TestAccAWSCodePipeline_disappears(t *testing.T) { } func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -165,14 +154,14 @@ func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_emptyStageArtifacts(name, githubToken), + Config: testAccAWSCodePipelineConfig_emptyStageArtifacts(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s$", name))), @@ -193,18 +182,12 @@ func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, }, }) } func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -212,14 +195,14 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_deployWithServiceRole(name, githubToken), + Config: testAccAWSCodePipelineConfig_deployWithServiceRole(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), resource.TestCheckResourceAttr(resourceName, "stage.2.name", "Deploy"), @@ -231,18 +214,12 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, }, }) } func TestAccAWSCodePipeline_tags(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p1, p2, p3 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -250,14 +227,14 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfigWithTags(name, githubToken, "tag1value", "tag2value"), + Config: testAccAWSCodePipelineConfigWithTags(name, "tag1value", "tag2value"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -270,13 +247,9 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, { - Config: testAccAWSCodePipelineConfigWithTags(name, githubToken, "tag1valueUpdate", "tag2valueUpdate"), + Config: testAccAWSCodePipelineConfigWithTags(name, "tag1valueUpdate", "tag2valueUpdate"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -289,13 +262,9 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, { - Config: testAccAWSCodePipelineConfig_basic(name, githubToken), + Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p3), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -306,8 +275,6 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { } func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" var providers []*schema.Provider @@ -318,14 +285,14 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t) testAccMultipleRegionPreCheck(t, 2) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t, testAccGetAlternateRegion()) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), + Config: testAccAWSCodePipelineConfig_multiregion(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -339,22 +306,16 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), + Config: testAccAWSCodePipelineConfig_multiregion(name), ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, }, }) } func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p1, p2 codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" var providers []*schema.Provider @@ -365,14 +326,14 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { PreCheck: func() { testAccPreCheck(t) testAccMultipleRegionPreCheck(t, 2) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t, testAccGetAlternateRegion()) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), + Config: testAccAWSCodePipelineConfig_multiregion(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -386,7 +347,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregionUpdated(name, githubToken), + Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -400,22 +361,16 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregionUpdated(name, githubToken), + Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, }, }) } func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p1, p2 codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" var providers []*schema.Provider @@ -426,14 +381,14 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { PreCheck: func() { testAccPreCheck(t) testAccMultipleRegionPreCheck(t, 2) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t, testAccGetAlternateRegion()) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_basic(name, githubToken), + Config: testAccAWSCodePipelineConfig_basic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), @@ -445,7 +400,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), + Config: testAccAWSCodePipelineConfig_multiregion(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -459,7 +414,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_backToBasic(name, githubToken), + Config: testAccAWSCodePipelineConfig_backToBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), @@ -471,22 +426,16 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_backToBasic(name, githubToken), + Config: testAccAWSCodePipelineConfig_backToBasic(name), ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, }, }) } func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { - githubToken := os.Getenv("GITHUB_TOKEN") - var p1 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -494,14 +443,14 @@ func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) + testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfigWithNamespace(name, githubToken), + Config: testAccAWSCodePipelineConfigWithNamespace(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), @@ -512,32 +461,28 @@ func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "stage.0.action.0.configuration.%", - "stage.0.action.0.configuration.OAuthToken", - }, }, }, }) } -func TestAccAWSCodePipeline_WithCodeStarConnection(t *testing.T) { +func TestAccAWSCodePipeline_WithGitHubv1SourceAction(t *testing.T) { var v codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" - codestarConnectionResourceName := "aws_codestarconnections_connection.test" + githubToken := os.Getenv("GITHUB_TOKEN") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) + testAccEnvironmentVariableSetPreCheck("GITHUB_TOKEN", t) testAccPreCheckAWSCodePipelineSupported(t) - testAccPartitionHasServicePreCheck(codestarconnections.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfigWithCodeStarConnection(name), + Config: testAccAWSCodePipelineConfig_WithGitHubv1SourceAction(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &v), @@ -545,19 +490,52 @@ func TestAccAWSCodePipeline_WithCodeStarConnection(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.category", "Source"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "AWS"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "CodeStarSourceConnection"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "ThirdParty"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "GitHub"), resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.version", "1"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.FullRepositoryId", "lifesum-terraform/test"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.BranchName", "main"), - resource.TestCheckResourceAttrPair(resourceName, "stage.0.action.0.configuration.ConnectionArn", codestarConnectionResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "4"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "lifesum-terraform"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "main"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "stage.0.action.0.configuration.%", + "stage.0.action.0.configuration.OAuthToken", + }, + }, + { + Config: testAccAWSCodePipelineConfig_WithGitHubv1SourceAction_Updated(name, githubToken), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &v), + + resource.TestCheckResourceAttr(resourceName, "stage.#", "2"), + + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.name", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.category", "Source"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.owner", "ThirdParty"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.provider", "GitHub"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.version", "1"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "4"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Owner", "test-terraform"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Repo", "test-repo"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.Branch", "stable"), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", githubToken), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "stage.0.action.0.configuration.%", + "stage.0.action.0.configuration.OAuthToken", + }, }, }, }) @@ -757,7 +735,7 @@ EOF `, rName) } -func testAccAWSCodePipelineConfig_basic(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_basic(rName string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), @@ -782,16 +760,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "main" - OAuthToken = %[2]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -813,10 +790,15 @@ resource "aws_codepipeline" "test" { } } } -`, rName, githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName)) } -func testAccAWSCodePipelineConfig_basicUpdated(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_basicUpdated(rName string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineS3Bucket("updated", rName), @@ -842,16 +824,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["artifacts"] configuration = { - Owner = "test-terraform" - Repo = "test-repo" - Branch = "stable" - OAuthToken = %[2]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "test-terraform/test-repo" + BranchName = "stable" } } } @@ -873,10 +854,15 @@ resource "aws_codepipeline" "test" { } } } -`, rName, githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName)) } -func testAccAWSCodePipelineConfig_emptyStageArtifacts(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_emptyStageArtifacts(rName string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), @@ -896,16 +882,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "main" - OAuthToken = %[2]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -928,7 +913,12 @@ resource "aws_codepipeline" "test" { } } } -`, rName, githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName)) } func testAccAWSCodePipelineDeployActionIAMRole(rName string) string { @@ -982,7 +972,7 @@ EOF `, rName) } -func testAccAWSCodePipelineConfig_deployWithServiceRole(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_deployWithServiceRole(rName string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRoleWithAssumeRole(rName), @@ -1008,16 +998,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["artifacts"] configuration = { - Owner = "test-terraform" - Repo = "test-repo" - Branch = "stable" - OAuthToken = %[2]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -1061,10 +1050,15 @@ resource "aws_codepipeline" "test" { } } } -`, rName, githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName)) } -func testAccAWSCodePipelineConfigWithTags(rName, githubToken, tag1, tag2 string) string { +func testAccAWSCodePipelineConfigWithTags(rName, tag1, tag2 string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), @@ -1089,16 +1083,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "main" - OAuthToken = %[4]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -1126,10 +1119,15 @@ resource "aws_codepipeline" "test" { tag2 = %[3]q } } -`, rName, tag1, tag2, githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName, tag1, tag2)) } -func testAccAWSCodePipelineConfig_multiregion(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_multiregion(rName string) string { return composeConfig( testAccAlternateRegionProviderConfig(), testAccAWSCodePipelineS3DefaultBucket(rName), @@ -1170,16 +1168,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "main" - OAuthToken = %[4]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -1216,10 +1213,15 @@ resource "aws_codepipeline" "test" { } } } -`, rName, testAccGetRegion(), testAccGetAlternateRegion(), githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName, testAccGetRegion(), testAccGetAlternateRegion())) } -func testAccAWSCodePipelineConfig_multiregionUpdated(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_multiregionUpdated(rName string) string { return composeConfig( testAccAlternateRegionProviderConfig(), testAccAWSCodePipelineS3DefaultBucket(rName), @@ -1260,16 +1262,15 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "main" - OAuthToken = %[4]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -1306,13 +1307,18 @@ resource "aws_codepipeline" "test" { } } } -`, rName, testAccGetRegion(), testAccGetAlternateRegion(), githubToken)) + +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} +`, rName, testAccGetRegion(), testAccGetAlternateRegion())) } -func testAccAWSCodePipelineConfig_backToBasic(rName, githubToken string) string { +func testAccAWSCodePipelineConfig_backToBasic(rName string) string { return composeConfig( testAccAlternateRegionProviderConfig(), - testAccAWSCodePipelineConfig_basic(rName, githubToken), + testAccAWSCodePipelineConfig_basic(rName), ) } @@ -1339,7 +1345,7 @@ resource "aws_s3_bucket" "%[1]s" { `, bucket, rName, provider) } -func testAccAWSCodePipelineConfigWithNamespace(rName, githubToken string) string { +func testAccAWSCodePipelineConfigWithNamespace(rName string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), @@ -1364,17 +1370,16 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "ThirdParty" - provider = "GitHub" + owner = "AWS" + provider = "CodeStarSourceConnection" version = "1" output_artifacts = ["test"] namespace = "SourceVariables" configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "main" - OAuthToken = %[2]q + ConnectionArn = aws_codestarconnections_connection.test.arn + FullRepositoryId = "lifesum-terraform/test" + BranchName = "main" } } } @@ -1397,14 +1402,19 @@ resource "aws_codepipeline" "test" { } } +resource "aws_codestarconnections_connection" "test" { + name = %[1]q + provider_type = "GitHub" +} + resource "aws_s3_bucket" "foo" { bucket = "tf-test-pipeline-%[1]s" acl = "private" } -`, rName, githubToken)) +`, rName)) } -func testAccAWSCodePipelineConfigWithCodeStarConnection(rName string) string { +func testAccAWSCodePipelineConfig_WithGitHubv1SourceAction(rName, githubToken string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), @@ -1429,15 +1439,16 @@ resource "aws_codepipeline" "test" { action { name = "Source" category = "Source" - owner = "AWS" - provider = "CodeStarSourceConnection" + owner = "ThirdParty" + provider = "GitHub" version = "1" output_artifacts = ["test"] configuration = { - ConnectionArn = aws_codestarconnections_connection.test.arn - FullRepositoryId = "lifesum-terraform/test" - BranchName = "main" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "main" + OAuthToken = %[2]q } } } @@ -1459,12 +1470,66 @@ resource "aws_codepipeline" "test" { } } } +`, rName, githubToken)) +} -resource "aws_codestarconnections_connection" "test" { - name = %[1]q - provider_type = "GitHub" +func testAccAWSCodePipelineConfig_WithGitHubv1SourceAction_Updated(rName, githubToken string) string { + return composeConfig( + testAccAWSCodePipelineS3DefaultBucket(rName), + testAccAWSCodePipelineServiceIAMRole(rName), + fmt.Sprintf(` +resource "aws_codepipeline" "test" { + name = "test-pipeline-%[1]s" + role_arn = aws_iam_role.codepipeline_role.arn + + artifact_store { + location = aws_s3_bucket.test.bucket + type = "S3" + + encryption_key { + id = "1234" + type = "KMS" + } + } + + stage { + name = "Source" + + action { + name = "Source" + category = "Source" + owner = "ThirdParty" + provider = "GitHub" + version = "1" + output_artifacts = ["artifacts"] + + configuration = { + Owner = "test-terraform" + Repo = "test-repo" + Branch = "stable" + OAuthToken = %[2]q + } + } + } + + stage { + name = "Build" + + action { + name = "Build" + category = "Build" + owner = "AWS" + provider = "CodeBuild" + input_artifacts = ["artifacts"] + version = "1" + + configuration = { + ProjectName = "test" + } + } + } } -`, rName)) +`, rName, githubToken)) } func TestResourceAWSCodePipelineExpandArtifactStoresValidation(t *testing.T) { From 4de8164929db1ed0611d0f6faa327a95e332e588 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 12 Jan 2021 15:56:00 -0800 Subject: [PATCH 5/5] Restores diff suppression for hashed GitHub tokens --- aws/resource_aws_codepipeline.go | 35 +++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index b66de0d158d..bc0ddb3732c 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -1,9 +1,12 @@ package aws import ( + "crypto/sha256" + "encoding/hex" "errors" "fmt" "log" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" @@ -104,9 +107,10 @@ func resourceAwsCodePipeline() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "configuration": { - Type: schema.TypeMap, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + DiffSuppressFunc: suppressCodePipelineStageActionConfiguration, }, "category": { Type: schema.TypeString, @@ -621,3 +625,28 @@ func resourceAwsCodePipelineValidateActionProvider(i interface{}, path cty.Path) return nil } + +func suppressCodePipelineStageActionConfiguration(k, old, new string, d *schema.ResourceData) bool { + parts := strings.Split(k, ".") + parts = parts[:len(parts)-2] + providerAddr := strings.Join(append(parts, "provider"), ".") + provider := d.Get(providerAddr).(string) + + if provider == CodePipelineProviderGitHub && strings.HasSuffix(k, CodePipelineGitHubActionConfigurationOAuthToken) { + hash := hashCodePipelineGitHubToken(new) + return old == hash + } + + return false +} + +const codePipelineGitHubTokenHashPrefix = "hash-" + +func hashCodePipelineGitHubToken(token string) string { + // Without this check, the value was getting encoded twice + if strings.HasPrefix(token, codePipelineGitHubTokenHashPrefix) { + return token + } + sum := sha256.Sum256([]byte(token)) + return codePipelineGitHubTokenHashPrefix + hex.EncodeToString(sum[:]) +}