From 48083f3aac01c332c1d1fd3c87285b47d748fb0e Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 13 Jul 2020 15:07:51 -0700 Subject: [PATCH 01/10] Code cleanup --- aws/resource_aws_codepipeline.go | 46 +++++++++++++++----------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 854e2b7661f..34ccaa0a93e 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -209,7 +209,7 @@ func resourceAwsCodePipelineCreate(d *schema.ResourceData, meta interface{}) err resp, err = conn.CreatePipeline(params) } if err != nil { - return fmt.Errorf("Error creating CodePipeline: %s", err) + return fmt.Errorf("Error creating CodePipeline: %w", err) } if resp.Pipeline == nil { return fmt.Errorf("Error creating CodePipeline: invalid response from AWS") @@ -297,12 +297,12 @@ func flattenAwsCodePipelineArtifactStore(artifactStore *codepipeline.ArtifactSto } values := map[string]interface{}{} - values["type"] = *artifactStore.Type - values["location"] = *artifactStore.Location + values["type"] = aws.StringValue(artifactStore.Type) + values["location"] = aws.StringValue(artifactStore.Location) if artifactStore.EncryptionKey != nil { as := map[string]interface{}{ - "id": *artifactStore.EncryptionKey.Id, - "type": *artifactStore.EncryptionKey.Type, + "id": aws.StringValue(artifactStore.EncryptionKey.Id), + "type": aws.StringValue(artifactStore.EncryptionKey.Type), } values["encryption_key"] = []interface{}{as} } @@ -339,7 +339,7 @@ func flattenAwsCodePipelineStages(stages []*codepipeline.StageDeclaration) []int stagesList := []interface{}{} for _, stage := range stages { values := map[string]interface{}{} - values["name"] = *stage.Name + values["name"] = aws.StringValue(stage.Name) values["action"] = flattenAwsCodePipelineStageActions(stage.Actions) stagesList = append(stagesList, values) } @@ -410,16 +410,16 @@ func flattenAwsCodePipelineStageActions(actions []*codepipeline.ActionDeclaratio actionsList := []interface{}{} for _, action := range actions { values := map[string]interface{}{ - "category": *action.ActionTypeId.Category, - "owner": *action.ActionTypeId.Owner, - "provider": *action.ActionTypeId.Provider, - "version": *action.ActionTypeId.Version, - "name": *action.Name, + "category": aws.StringValue(action.ActionTypeId.Category), + "owner": aws.StringValue(action.ActionTypeId.Owner), + "provider": aws.StringValue(action.ActionTypeId.Provider), + "version": aws.StringValue(action.ActionTypeId.Version), + "name": aws.StringValue(action.Name), } if action.Configuration != nil { config := flattenAwsCodePipelineStageActionConfiguration(action.Configuration) _, ok := config["OAuthToken"] - actionProvider := *action.ActionTypeId.Provider + actionProvider := aws.StringValue(action.ActionTypeId.Provider) if ok && actionProvider == "GitHub" { delete(config, "OAuthToken") } @@ -435,15 +435,15 @@ func flattenAwsCodePipelineStageActions(actions []*codepipeline.ActionDeclaratio } if action.RoleArn != nil { - values["role_arn"] = *action.RoleArn + values["role_arn"] = aws.StringValue(action.RoleArn) } if action.RunOrder != nil { - values["run_order"] = int(*action.RunOrder) + values["run_order"] = int(aws.Int64Value(action.RunOrder)) } if action.Region != nil { - values["region"] = *action.Region + values["region"] = aws.StringValue(action.Region) } if action.Namespace != nil { @@ -523,13 +523,13 @@ func resourceAwsCodePipelineRead(d *schema.ResourceData, meta interface{}) error }) if isAWSErr(err, codepipeline.ErrCodePipelineNotFoundException, "") { - log.Printf("[WARN] Codepipeline (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] CodePipeline (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading Codepipeline: %s", err) + return fmt.Errorf("error reading CodePipeline: %w", err) } metadata := resp.Metadata @@ -557,11 +557,11 @@ func resourceAwsCodePipelineRead(d *schema.ResourceData, meta interface{}) error tags, err := keyvaluetags.CodepipelineListTags(conn, arn) if err != nil { - return fmt.Errorf("error listing tags for Codepipeline (%s): %s", arn, err) + return fmt.Errorf("error listing tags for CodePipeline (%s): %w", arn, err) } if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("error setting tags for CodePipeline (%s): %w", arn, err) } return nil @@ -580,9 +580,7 @@ func resourceAwsCodePipelineUpdate(d *schema.ResourceData, meta interface{}) err _, err = conn.UpdatePipeline(params) if err != nil { - return fmt.Errorf( - "[ERROR] Error updating CodePipeline (%s): %s", - d.Id(), err) + return fmt.Errorf("[ERROR] Error updating CodePipeline (%s): %w", d.Id(), err) } arn := d.Get("arn").(string) @@ -590,7 +588,7 @@ func resourceAwsCodePipelineUpdate(d *schema.ResourceData, meta interface{}) err o, n := d.GetChange("tags") if err := keyvaluetags.CodepipelineUpdateTags(conn, arn, o, n); err != nil { - return fmt.Errorf("error updating Codepipeline (%s) tags: %s", arn, err) + return fmt.Errorf("error updating CodePipeline (%s) tags: %w", arn, err) } } @@ -609,7 +607,7 @@ func resourceAwsCodePipelineDelete(d *schema.ResourceData, meta interface{}) err } if err != nil { - return fmt.Errorf("error deleting Codepipeline (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting CodePipeline (%s): %w", d.Id(), err) } return err From 04685068856cd54fc30502bab1d5e5902828ae97 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 14 Jul 2020 11:44:13 -0700 Subject: [PATCH 02/10] Removes `GITHUB_TOKEN` environment variable requirement for CodePipeline and adds drift detection to GitHub action OAuthToken --- aws/resource_aws_codepipeline.go | 82 +++++++--- aws/resource_aws_codepipeline_test.go | 226 ++++++++++++++++++-------- website/docs/r/codepipeline.markdown | 135 ++++++++------- 3 files changed, 278 insertions(+), 165 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 34ccaa0a93e..c0c6eaa0e42 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -1,10 +1,12 @@ package aws import ( + "crypto/sha256" + "encoding/hex" "errors" "fmt" "log" - "os" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/codepipeline" @@ -15,6 +17,12 @@ import ( iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) +const ( + CodePipelineProviderGitHub = "GitHub" + + CodePipelineGitHubActionConfigurationOAuthToken = "OAuthToken" +) + func resourceAwsCodePipeline() *schema.Resource { return &schema.Resource{ Create: resourceAwsCodePipelineCreate, @@ -101,9 +109,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, @@ -320,10 +329,10 @@ func flattenAwsCodePipelineArtifactStores(artifactStores map[string]*codepipelin } func expandAwsCodePipelineStages(d *schema.ResourceData) []*codepipeline.StageDeclaration { - configs := d.Get("stage").([]interface{}) + stages := d.Get("stage").([]interface{}) pipelineStages := []*codepipeline.StageDeclaration{} - for _, stage := range configs { + for _, stage := range stages { data := stage.(map[string]interface{}) a := data["action"].([]interface{}) actions := expandAwsCodePipelineActions(a) @@ -335,31 +344,23 @@ func expandAwsCodePipelineStages(d *schema.ResourceData) []*codepipeline.StageDe return pipelineStages } -func flattenAwsCodePipelineStages(stages []*codepipeline.StageDeclaration) []interface{} { +func flattenAwsCodePipelineStages(stages []*codepipeline.StageDeclaration, d *schema.ResourceData) []interface{} { stagesList := []interface{}{} - for _, stage := range stages { + for si, stage := range stages { values := map[string]interface{}{} values["name"] = aws.StringValue(stage.Name) - values["action"] = flattenAwsCodePipelineStageActions(stage.Actions) + values["action"] = flattenAwsCodePipelineStageActions(si, stage.Actions, d) stagesList = append(stagesList, values) } return stagesList - } -func expandAwsCodePipelineActions(s []interface{}) []*codepipeline.ActionDeclaration { +func expandAwsCodePipelineActions(a []interface{}) []*codepipeline.ActionDeclaration { actions := []*codepipeline.ActionDeclaration{} - for _, config := range s { + for _, config := range a { data := config.(map[string]interface{}) conf := expandAwsCodePipelineStageActionConfiguration(data["configuration"].(map[string]interface{})) - if data["provider"].(string) == "GitHub" { - githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken != "" { - conf["OAuthToken"] = aws.String(githubToken) - } - - } action := codepipeline.ActionDeclaration{ ActionTypeId: &codepipeline.ActionTypeId{ @@ -406,9 +407,9 @@ func expandAwsCodePipelineActions(s []interface{}) []*codepipeline.ActionDeclara return actions } -func flattenAwsCodePipelineStageActions(actions []*codepipeline.ActionDeclaration) []interface{} { +func flattenAwsCodePipelineStageActions(si int, actions []*codepipeline.ActionDeclaration, d *schema.ResourceData) []interface{} { actionsList := []interface{}{} - for _, action := range actions { + for ai, action := range actions { values := map[string]interface{}{ "category": aws.StringValue(action.ActionTypeId.Category), "owner": aws.StringValue(action.ActionTypeId.Owner), @@ -418,11 +419,17 @@ func flattenAwsCodePipelineStageActions(actions []*codepipeline.ActionDeclaratio } if action.Configuration != nil { config := flattenAwsCodePipelineStageActionConfiguration(action.Configuration) - _, ok := config["OAuthToken"] + actionProvider := aws.StringValue(action.ActionTypeId.Provider) - if ok && actionProvider == "GitHub" { - delete(config, "OAuthToken") + if actionProvider == CodePipelineProviderGitHub { + 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 + } } + values["configuration"] = config } @@ -545,7 +552,7 @@ func resourceAwsCodePipelineRead(d *schema.ResourceData, meta interface{}) error } } - if err := d.Set("stage", flattenAwsCodePipelineStages(pipeline.Stages)); err != nil { + if err := d.Set("stage", flattenAwsCodePipelineStages(pipeline.Stages, d)); err != nil { return err } @@ -612,3 +619,28 @@ 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 + } + + 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[:]) +} diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 6615b740253..da6cc77f533 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -15,6 +15,11 @@ import ( ) func TestAccAWSCodePipeline_basic(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p1, p2 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -25,7 +30,7 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_basic(name), + Config: testAccAWSCodePipelineConfig_basic(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttrPair(resourceName, "role_arn", "aws_iam_role.codepipeline_role", "arn"), @@ -44,10 +49,11 @@ 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", "test"), - resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.%", "3"), + 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.OAuthToken", hashCodePipelineGitHubToken(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", ""), @@ -73,9 +79,13 @@ 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), + Config: testAccAWSCodePipelineConfig_basicUpdated(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), @@ -87,10 +97,11 @@ 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.%", "3"), + 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", hashCodePipelineGitHubToken(githubToken)), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), @@ -105,12 +116,21 @@ 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", + }, }, }, }) } func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -121,7 +141,7 @@ func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_emptyStageArtifacts(name), + Config: testAccAWSCodePipelineConfig_emptyStageArtifacts(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s$", name))), @@ -142,12 +162,21 @@ 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") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -158,7 +187,7 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_deployWithServiceRole(name), + Config: testAccAWSCodePipelineConfig_deployWithServiceRole(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), resource.TestCheckResourceAttr(resourceName, "stage.2.name", "Deploy"), @@ -170,12 +199,21 @@ 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") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p1, p2, p3 codepipeline.PipelineDeclaration name := acctest.RandString(10) resourceName := "aws_codepipeline.test" @@ -186,7 +224,7 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfigWithTags(name, "tag1value", "tag2value"), + Config: testAccAWSCodePipelineConfigWithTags(name, githubToken, "tag1value", "tag2value"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -199,9 +237,13 @@ 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, "tag1valueUpdate", "tag2valueUpdate"), + Config: testAccAWSCodePipelineConfigWithTags(name, githubToken, "tag1valueUpdate", "tag2valueUpdate"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -214,9 +256,13 @@ 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), + Config: testAccAWSCodePipelineConfig_basic(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p3), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -227,6 +273,11 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { } func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" var providers []*schema.Provider @@ -244,7 +295,7 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_multiregion(name), + Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -258,16 +309,25 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregion(name), + Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), 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") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p1, p2 codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" var providers []*schema.Provider @@ -285,7 +345,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_multiregion(name), + Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -299,7 +359,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), + Config: testAccAWSCodePipelineConfig_multiregionUpdated(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -313,16 +373,25 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregionUpdated(name), + Config: testAccAWSCodePipelineConfig_multiregionUpdated(name, githubToken), 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") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + var p1, p2 codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" var providers []*schema.Provider @@ -340,7 +409,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfig_basic(name), + Config: testAccAWSCodePipelineConfig_basic(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), @@ -352,7 +421,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_multiregion(name), + Config: testAccAWSCodePipelineConfig_multiregion(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p2), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "2"), @@ -366,7 +435,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_backToBasic(name), + Config: testAccAWSCodePipelineConfig_backToBasic(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), resource.TestCheckResourceAttr(resourceName, "artifact_store.#", "1"), @@ -378,17 +447,22 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineConfig_backToBasic(name), + Config: testAccAWSCodePipelineConfig_backToBasic(name, githubToken), 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) { - if os.Getenv("GITHUB_TOKEN") == "" { + githubToken := os.Getenv("GITHUB_TOKEN") + if githubToken == "" { t.Skip("Environment variable GITHUB_TOKEN is not set") } @@ -402,7 +476,7 @@ func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineConfigWithNamespace(name), + Config: testAccAWSCodePipelineConfigWithNamespace(name, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineExists(resourceName, &p1), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "codepipeline", regexp.MustCompile(fmt.Sprintf("test-pipeline-%s", name))), @@ -413,6 +487,10 @@ 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", + }, }, }, }) @@ -469,10 +547,6 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { } func testAccPreCheckAWSCodePipeline(t *testing.T) { - if os.Getenv("GITHUB_TOKEN") == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } - conn := testAccProvider.Meta().(*AWSClient).codepipelineconn input := &codepipeline.ListPipelinesInput{} @@ -607,13 +681,13 @@ EOF `, rName) } -func testAccAWSCodePipelineConfig_basic(rName string) string { +func testAccAWSCodePipelineConfig_basic(rName, githubToken string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), fmt.Sprintf(` resource "aws_codepipeline" "test" { - name = "test-pipeline-%s" + name = "test-pipeline-%[1]s" role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { @@ -638,9 +712,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" + OAuthToken = %[2]q } } } @@ -662,10 +737,10 @@ resource "aws_codepipeline" "test" { } } } -`, rName)) +`, rName, githubToken)) } -func testAccAWSCodePipelineConfig_basicUpdated(rName string) string { +func testAccAWSCodePipelineConfig_basicUpdated(rName, githubToken string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineS3Bucket("updated", rName), @@ -697,9 +772,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["artifacts"] configuration = { - Owner = "test-terraform" - Repo = "test-repo" - Branch = "stable" + Owner = "test-terraform" + Repo = "test-repo" + Branch = "stable" + OAuthToken = %[2]q } } } @@ -721,16 +797,16 @@ resource "aws_codepipeline" "test" { } } } -`, rName)) +`, rName, githubToken)) } -func testAccAWSCodePipelineConfig_emptyStageArtifacts(rName string) string { +func testAccAWSCodePipelineConfig_emptyStageArtifacts(rName, githubToken string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), fmt.Sprintf(` resource "aws_codepipeline" "test" { - name = "test-pipeline-%s" + name = "test-pipeline-%[1]s" role_arn = "${aws_iam_role.codepipeline_role.arn}" artifact_store { @@ -750,9 +826,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" + OAuthToken = %[2]q } } } @@ -775,7 +852,7 @@ resource "aws_codepipeline" "test" { } } } -`, rName)) +`, rName, githubToken)) } func testAccAWSCodePipelineDeployActionIAMRole(rName string) string { @@ -828,7 +905,7 @@ EOF `, rName) } -func testAccAWSCodePipelineConfig_deployWithServiceRole(rName string) string { +func testAccAWSCodePipelineConfig_deployWithServiceRole(rName, githubToken string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRoleWithAssumeRole(rName), @@ -860,9 +937,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["artifacts"] configuration = { - Owner = "test-terraform" - Repo = "test-repo" - Branch = "stable" + Owner = "test-terraform" + Repo = "test-repo" + Branch = "stable" + OAuthToken = %[2]q } } } @@ -906,10 +984,10 @@ resource "aws_codepipeline" "test" { } } } -`, rName)) +`, rName, githubToken)) } -func testAccAWSCodePipelineConfigWithTags(rName, tag1, tag2 string) string { +func testAccAWSCodePipelineConfigWithTags(rName, githubToken, tag1, tag2 string) string { return composeConfig( testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), @@ -940,9 +1018,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" + OAuthToken = %[4]q } } } @@ -970,10 +1049,10 @@ resource "aws_codepipeline" "test" { tag2 = %[3]q } } -`, rName, tag1, tag2)) +`, rName, tag1, tag2, githubToken)) } -func testAccAWSCodePipelineConfig_multiregion(rName string) string { +func testAccAWSCodePipelineConfig_multiregion(rName, githubToken string) string { return composeConfig( testAccAlternateRegionProviderConfig(), testAccAWSCodePipelineS3DefaultBucket(rName), @@ -1068,9 +1147,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" + OAuthToken = %[4]q } } } @@ -1105,10 +1185,10 @@ resource "aws_codepipeline" "test" { } } } -`, rName, testAccGetRegion(), testAccGetAlternateRegion())) +`, rName, testAccGetRegion(), testAccGetAlternateRegion(), githubToken)) } -func testAccAWSCodePipelineConfig_multiregionUpdated(rName string) string { +func testAccAWSCodePipelineConfig_multiregionUpdated(rName, githubToken string) string { return composeConfig( testAccAlternateRegionProviderConfig(), testAccAWSCodePipelineS3DefaultBucket(rName), @@ -1203,9 +1283,10 @@ resource "aws_codepipeline" "test" { output_artifacts = ["test"] configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" + OAuthToken = %[4]q } } } @@ -1240,13 +1321,13 @@ resource "aws_codepipeline" "test" { } } } -`, rName, testAccGetRegion(), testAccGetAlternateRegion())) +`, rName, testAccGetRegion(), testAccGetAlternateRegion(), githubToken)) } -func testAccAWSCodePipelineConfig_backToBasic(rName string) string { +func testAccAWSCodePipelineConfig_backToBasic(rName, githubToken string) string { return composeConfig( testAccAlternateRegionProviderConfig(), - testAccAWSCodePipelineConfig_basic(rName), + testAccAWSCodePipelineConfig_basic(rName, githubToken), ) } @@ -1266,14 +1347,14 @@ resource "aws_s3_bucket" "%[1]s" { func testAccAWSCodePipelineS3BucketWithProvider(bucket, rName, provider string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "%[1]s" { - bucket = "tf-test-pipeline-%[1]s-%[2]s" - acl = "private" + bucket = "tf-test-pipeline-%[1]s-%[2]s" + acl = "private" provider = %[3]s } `, bucket, rName, provider) } -func testAccAWSCodePipelineConfigWithNamespace(rName string) string { +func testAccAWSCodePipelineConfigWithNamespace(rName, githubToken string) string { return fmt.Sprintf(` resource "aws_codepipeline" "test" { name = "test-pipeline-%[1]s" @@ -1302,9 +1383,10 @@ resource "aws_codepipeline" "test" { namespace = "SourceVariables" configuration = { - Owner = "lifesum-terraform" - Repo = "test" - Branch = "master" + Owner = "lifesum-terraform" + Repo = "test" + Branch = "master" + OAuthToken = %[2]q } } } @@ -1383,7 +1465,7 @@ resource "aws_iam_role_policy" "codepipeline_policy" { } EOF } -`, rName) +`, rName, githubToken) } func TestResourceAWSCodePipelineExpandArtifactStoresValidation(t *testing.T) { @@ -1492,14 +1574,14 @@ func TestResourceAWSCodePipelineExpandArtifactStoresValidation(t *testing.T) { _, err := expandAwsCodePipelineArtifactStores(tc.Input) if tc.ExpectedError == "" { if err != nil { - t.Errorf("%s: Did not expect an error, but got: %q", tc.Name, err) + t.Errorf("%s: Did not expect an error, but got: %w", tc.Name, err) } } else { if err == nil { t.Errorf("%s: Expected an error, but did not get one", tc.Name) } else { if err.Error() != tc.ExpectedError { - t.Errorf("%s: Expected error %q, got %q", tc.Name, tc.ExpectedError, err.Error()) + t.Errorf("%s: Expected error %q, got %w", tc.Name, tc.ExpectedError, err) } } } diff --git a/website/docs/r/codepipeline.markdown b/website/docs/r/codepipeline.markdown index a888a083e8c..9c2a0538de9 100644 --- a/website/docs/r/codepipeline.markdown +++ b/website/docs/r/codepipeline.markdown @@ -10,73 +10,9 @@ description: |- Provides a CodePipeline. -~> **NOTE on `aws_codepipeline`:** - the `GITHUB_TOKEN` environment variable must be set if the GitHub provider is specified. - ## Example Usage ```hcl -resource "aws_s3_bucket" "codepipeline_bucket" { - bucket = "test-bucket" - acl = "private" -} - -resource "aws_iam_role" "codepipeline_role" { - name = "test-role" - - assume_role_policy = < Date: Tue, 14 Jul 2020 11:53:51 -0700 Subject: [PATCH 03/10] Updates usage example in documentation for Terraform 0.12 --- website/docs/r/codepipeline.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/r/codepipeline.markdown b/website/docs/r/codepipeline.markdown index 9c2a0538de9..377580c1567 100644 --- a/website/docs/r/codepipeline.markdown +++ b/website/docs/r/codepipeline.markdown @@ -109,11 +109,12 @@ resource "aws_iam_role" "codepipeline_role" { ] } EOF + } resource "aws_iam_role_policy" "codepipeline_policy" { name = "codepipeline_policy" - role = "${aws_iam_role.codepipeline_role.id}" + role = aws_iam_role.codepipeline_role.id policy = < Date: Tue, 14 Jul 2020 12:20:00 -0700 Subject: [PATCH 04/10] Adds disappears test and cleans up test configurations --- aws/resource_aws_codepipeline_test.go | 204 +++++--------------------- 1 file changed, 38 insertions(+), 166 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index da6cc77f533..6bcbfe9c2dc 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -125,6 +125,33 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { }) } +func TestAccAWSCodePipeline_disappears(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + if githubToken == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + + var p codepipeline.PipelineDeclaration + name := acctest.RandString(10) + resourceName := "aws_codepipeline.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCodePipeline(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCodePipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCodePipelineConfig_basic(name, githubToken), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCodePipelineExists(resourceName, &p), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCodePipeline(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") if githubToken == "" { @@ -565,7 +592,7 @@ func testAccPreCheckAWSCodePipeline(t *testing.T) { func testAccAWSCodePipelineServiceIAMRole(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "codepipeline_role" { - name = "codepipeline-role-%s" + name = "codepipeline-role-%[1]s" assume_role_policy = < Date: Tue, 14 Jul 2020 14:08:33 -0700 Subject: [PATCH 05/10] Updates tests for GovCloud --- aws/resource_aws_codepipeline_test.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 6bcbfe9c2dc..fdaef53ee99 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -317,6 +317,7 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) testAccPreCheckAWSCodePipeline(t) + testAccPreCheckAWSCodePipelineAlternateRegion(t) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -367,6 +368,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) testAccPreCheckAWSCodePipeline(t) + testAccPreCheckAWSCodePipelineAlternateRegion(t) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -431,6 +433,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) testAccPreCheckAWSCodePipeline(t) + testAccPreCheckAWSCodePipelineAlternateRegion(t) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -589,6 +592,25 @@ func testAccPreCheckAWSCodePipeline(t *testing.T) { } } +func testAccPreCheckAWSCodePipelineAlternateRegion(t *testing.T) { + // There isn't a way to get the alternate region provider at PreCheck time, so hardcode it + if testAccGetAlternateRegion() == "us-gov-east-1" { + + t.Skipf(`skipping acceptance testing: + +Test provider region (us-gov-east-1) does not support AWS CodePipeline. + +The allowed regions are hardcoded in the acceptance testing since there isn't a convenientway to check for +support in alternate regions. If this check is out of date, please create an issue in the Terraform AWS Provider +repository (https://github.com/terraform-providers/terraform-provider-aws) or submit a PR to update the +check itself (testAccPreCheckAWSCodePipelineAlternateRegion). + +For the most up to date supported region information, see the GovCloud AWS CodePipeline User Guide: +https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-acp.html +`) + } +} + func testAccAWSCodePipelineServiceIAMRole(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "codepipeline_role" { @@ -885,6 +907,7 @@ resource "aws_codepipeline" "test" { func testAccAWSCodePipelineDeployActionIAMRole(rName string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} resource "aws_iam_role" "codepipeline_action_role" { name = "codepipeline-action-role-%s" @@ -896,7 +919,7 @@ resource "aws_iam_role" "codepipeline_action_role" { { "Effect": "Allow", "Principal": { - "AWS": "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + "AWS": "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" }, "Action": "sts:AssumeRole" } From 438deca89b660cc79a25cbcb1a692be78b5ec325 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 15 Jul 2020 11:56:36 -0700 Subject: [PATCH 06/10] Updates `PreCheck` to try API call in acceptance test regions --- aws/resource_aws_codepipeline_test.go | 56 +++++++++++---------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index fdaef53ee99..1117cd0df1e 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -316,8 +316,7 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { testAccPreCheck(t) testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) - testAccPreCheckAWSCodePipeline(t) - testAccPreCheckAWSCodePipelineAlternateRegion(t) + testAccPreCheckAWSCodePipeline(t, testAccGetAlternateRegion()) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -367,8 +366,7 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { testAccPreCheck(t) testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) - testAccPreCheckAWSCodePipeline(t) - testAccPreCheckAWSCodePipelineAlternateRegion(t) + testAccPreCheckAWSCodePipeline(t, testAccGetAlternateRegion()) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -432,8 +430,7 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { testAccPreCheck(t) testAccMultipleRegionsPreCheck(t) testAccAlternateRegionPreCheck(t) - testAccPreCheckAWSCodePipeline(t) - testAccPreCheckAWSCodePipelineAlternateRegion(t) + testAccPreCheckAWSCodePipeline(t, testAccGetAlternateRegion()) }, ProviderFactories: testAccProviderFactories(&providers), CheckDestroy: testAccCheckAWSCodePipelineDestroy, @@ -576,38 +573,29 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { return nil } -func testAccPreCheckAWSCodePipeline(t *testing.T) { - conn := testAccProvider.Meta().(*AWSClient).codepipelineconn - - input := &codepipeline.ListPipelinesInput{} - - _, err := conn.ListPipelines(input) - - if testAccPreCheckSkipError(err) { - t.Skipf("skipping acceptance testing: %s", err) - } - - if err != nil { - t.Fatalf("unexpected PreCheck error: %s", err) - } -} +func testAccPreCheckAWSCodePipeline(t *testing.T, regions ...string) { + regions = append(regions, testAccGetRegion()) -func testAccPreCheckAWSCodePipelineAlternateRegion(t *testing.T) { - // There isn't a way to get the alternate region provider at PreCheck time, so hardcode it - if testAccGetAlternateRegion() == "us-gov-east-1" { - - t.Skipf(`skipping acceptance testing: + for _, region := range regions { + conf := &Config{ + Region: region, + } + client, err := conf.Client() + if err != nil { + t.Fatalf("error getting AWS client for region %s", region) + } + conn := client.(*AWSClient).codepipelineconn -Test provider region (us-gov-east-1) does not support AWS CodePipeline. + input := &codepipeline.ListPipelinesInput{} + _, err = conn.ListPipelines(input) -The allowed regions are hardcoded in the acceptance testing since there isn't a convenientway to check for -support in alternate regions. If this check is out of date, please create an issue in the Terraform AWS Provider -repository (https://github.com/terraform-providers/terraform-provider-aws) or submit a PR to update the -check itself (testAccPreCheckAWSCodePipelineAlternateRegion). + if testAccPreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } -For the most up to date supported region information, see the GovCloud AWS CodePipeline User Guide: -https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-acp.html -`) + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } } } From 22e5d58cfd3a036a5a521dffc7c5b22e84460d67 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 15 Jul 2020 12:02:39 -0700 Subject: [PATCH 07/10] Adds Version 3 Upgrade documentation --- website/docs/guides/version-3-upgrade.html.md | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/website/docs/guides/version-3-upgrade.html.md b/website/docs/guides/version-3-upgrade.html.md index f84db6f864f..10952be22b6 100644 --- a/website/docs/guides/version-3-upgrade.html.md +++ b/website/docs/guides/version-3-upgrade.html.md @@ -30,6 +30,7 @@ Upgrade topics: - [Resource: aws_autoscaling_group](#resource-aws_autoscaling_group) - [Resource: aws_cloudfront_distribution](#resource-aws_cloudfront_distribution) - [Resource: aws_cloudwatch_log_group](#resource-aws_cloudwatch_log_group) +- [Resource: aws_codepipeline](#resource-aws_codepipeline) - [Resource: aws_cognito_user_pool](#resource-aws_cognito_user_pool) - [Resource: aws_dx_gateway](#resource-aws_dx_gateway) - [Resource: aws_dx_gateway_association](#resource-aws_dx_gateway_association) @@ -717,6 +718,75 @@ data "aws_iam_policy_document" "ad-log-policy" { } ``` +## Resource: aws_codepipeline + +### GITHUB_TOKEN environment variable removal + +Switch your Terraform configuration to the `OAuthToken` element in the `action` `configuration` map instead. + +For example, given this previous configuration: + +```bash +$ GITHUB_TOKEN= terraform apply +``` + +```hcl +resource "aws_codepipeline" "example" { + # ... other configuration ... + + stage { + name = "Source" + + action { + name = "Source" + category = "Source" + owner = "ThirdParty" + provider = "GitHub" + version = "1" + output_artifacts = ["example"] + + configuration = { + Owner = "lifesum-terraform" + Repo = "example" + Branch = "main" + } + } + } +} +``` + +```bash +$ TF_VAR_github_token= terraform apply +``` + +```hcl +variable "github_token" {} + +resource "aws_codepipeline" "example" { + # ... other configuration ... + + stage { + name = "Source" + + action { + name = "Source" + category = "Source" + owner = "ThirdParty" + provider = "GitHub" + version = "1" + output_artifacts = ["example"] + + configuration = { + Owner = "lifesum-terraform" + Repo = "example" + Branch = "main" + OAuthToken = var.github_token + } + } + } +} +``` + ## Resource: aws_cognito_user_pool ### Removal of admin_create_user_config.unused_account_validity_days Argument From fa9628f79892f04d03570eb1e1fe3a7fe61d378e Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 29 Jul 2020 22:52:33 -0700 Subject: [PATCH 08/10] Removes hashing from GitHub `OAuthToken` and marks `configuration` sensitive --- aws/resource_aws_codepipeline.go | 40 ++++----------------------- aws/resource_aws_codepipeline_test.go | 4 +-- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index c0c6eaa0e42..008238a30a8 100644 --- a/aws/resource_aws_codepipeline.go +++ b/aws/resource_aws_codepipeline.go @@ -1,12 +1,9 @@ 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" @@ -109,10 +106,11 @@ 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, + // Some configuration types can contain sensitive values, such as a GitHub OAuthToken + Sensitive: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, "category": { Type: schema.TypeString, @@ -425,8 +423,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) } } @@ -619,28 +616,3 @@ 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 - } - - 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[:]) -} diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 1117cd0df1e..6a9832a2bf8 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -53,7 +53,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", ""), @@ -101,7 +101,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"), From 2f0704c303926cb5cf64c520490725ca9d735130 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 30 Jul 2020 17:08:49 -0700 Subject: [PATCH 09/10] Revert "Removes hashing from GitHub `OAuthToken` and marks `configuration` sensitive" This reverts commit 91534098ae29a9d2b56f271b3baf0a618aa55d7d. --- aws/resource_aws_codepipeline.go | 40 +++++++++++++++++++++++---- aws/resource_aws_codepipeline_test.go | 4 +-- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_codepipeline.go b/aws/resource_aws_codepipeline.go index 008238a30a8..c0c6eaa0e42 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" @@ -106,11 +109,10 @@ func resourceAwsCodePipeline() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "configuration": { - Type: schema.TypeMap, - Optional: true, - // Some configuration types can contain sensitive values, such as a GitHub OAuthToken - Sensitive: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + DiffSuppressFunc: suppressCodePipelineStageActionConfiguration, }, "category": { Type: schema.TypeString, @@ -423,7 +425,8 @@ 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) - config[CodePipelineGitHubActionConfigurationOAuthToken] = d.Get(addr).(string) + hash := hashCodePipelineGitHubToken(d.Get(addr).(string)) + config[CodePipelineGitHubActionConfigurationOAuthToken] = hash } } @@ -616,3 +619,28 @@ 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 + } + + 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[:]) +} diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 6a9832a2bf8..1117cd0df1e 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -53,7 +53,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", githubToken), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", hashCodePipelineGitHubToken(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", ""), @@ -101,7 +101,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", githubToken), + resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.configuration.OAuthToken", hashCodePipelineGitHubToken(githubToken)), resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Build"), resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", "1"), From c2e885fd560e062f16c160b2d5248bb7b4005bcf Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 30 Jul 2020 18:12:21 -0700 Subject: [PATCH 10/10] Updates provider for multiregion tests and adds OAuthToken to CodePipeline Webhook tests --- aws/resource_aws_codepipeline_test.go | 36 +++---------- aws/resource_aws_codepipeline_webhook_test.go | 54 +++++++++++-------- 2 files changed, 39 insertions(+), 51 deletions(-) diff --git a/aws/resource_aws_codepipeline_test.go b/aws/resource_aws_codepipeline_test.go index 1117cd0df1e..1395e1fb8ca 100644 --- a/aws/resource_aws_codepipeline_test.go +++ b/aws/resource_aws_codepipeline_test.go @@ -16,9 +16,6 @@ import ( func TestAccAWSCodePipeline_basic(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p1, p2 codepipeline.PipelineDeclaration name := acctest.RandString(10) @@ -127,9 +124,6 @@ func TestAccAWSCodePipeline_basic(t *testing.T) { func TestAccAWSCodePipeline_disappears(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p codepipeline.PipelineDeclaration name := acctest.RandString(10) @@ -154,9 +148,6 @@ func TestAccAWSCodePipeline_disappears(t *testing.T) { func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p codepipeline.PipelineDeclaration name := acctest.RandString(10) @@ -200,9 +191,6 @@ func TestAccAWSCodePipeline_emptyStageArtifacts(t *testing.T) { func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p codepipeline.PipelineDeclaration name := acctest.RandString(10) @@ -237,9 +225,6 @@ func TestAccAWSCodePipeline_deployWithServiceRole(t *testing.T) { func TestAccAWSCodePipeline_tags(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p1, p2, p3 codepipeline.PipelineDeclaration name := acctest.RandString(10) @@ -301,9 +286,6 @@ func TestAccAWSCodePipeline_tags(t *testing.T) { func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" @@ -351,9 +333,6 @@ func TestAccAWSCodePipeline_multiregion_basic(t *testing.T) { func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p1, p2 codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" @@ -415,9 +394,6 @@ func TestAccAWSCodePipeline_multiregion_Update(t *testing.T) { func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p1, p2 codepipeline.PipelineDeclaration resourceName := "aws_codepipeline.test" @@ -489,9 +465,6 @@ func TestAccAWSCodePipeline_multiregion_ConvertSingleRegion(t *testing.T) { func TestAccAWSCodePipeline_WithNamespace(t *testing.T) { githubToken := os.Getenv("GITHUB_TOKEN") - if githubToken == "" { - t.Skip("Environment variable GITHUB_TOKEN is not set") - } var p1 codepipeline.PipelineDeclaration name := acctest.RandString(10) @@ -574,8 +547,11 @@ func testAccCheckAWSCodePipelineDestroy(s *terraform.State) error { } func testAccPreCheckAWSCodePipeline(t *testing.T, regions ...string) { - regions = append(regions, testAccGetRegion()) + if os.Getenv("GITHUB_TOKEN") == "" { + t.Skip("Environment variable GITHUB_TOKEN is not set") + } + regions = append(regions, testAccGetRegion()) for _, region := range regions { conf := &Config{ Region: region, @@ -1095,7 +1071,7 @@ func testAccAWSCodePipelineConfig_multiregion(rName, githubToken string) string testAccAlternateRegionProviderConfig(), testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), - testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "aws.alternate"), + testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "awsalternate"), fmt.Sprintf(` resource "aws_codepipeline" "test" { name = "test-pipeline-%[1]s" @@ -1178,7 +1154,7 @@ func testAccAWSCodePipelineConfig_multiregionUpdated(rName, githubToken string) testAccAlternateRegionProviderConfig(), testAccAWSCodePipelineS3DefaultBucket(rName), testAccAWSCodePipelineServiceIAMRole(rName), - testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "aws.alternate"), + testAccAWSCodePipelineS3BucketWithProvider("alternate", rName, "awsalternate"), fmt.Sprintf(` resource "aws_codepipeline" "test" { name = "test-pipeline-%[1]s" diff --git a/aws/resource_aws_codepipeline_webhook_test.go b/aws/resource_aws_codepipeline_webhook_test.go index bda745d7ccd..ee8eb979253 100644 --- a/aws/resource_aws_codepipeline_webhook_test.go +++ b/aws/resource_aws_codepipeline_webhook_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "os" "testing" "github.com/aws/aws-sdk-go/aws" @@ -12,6 +13,8 @@ import ( ) func TestAccAWSCodePipelineWebhook_basic(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + var v codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" @@ -22,7 +25,7 @@ func TestAccAWSCodePipelineWebhook_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineWebhookConfig_basic(rName), + Config: testAccAWSCodePipelineWebhookConfig_basic(rName, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -41,6 +44,8 @@ func TestAccAWSCodePipelineWebhook_basic(t *testing.T) { } func TestAccAWSCodePipelineWebhook_ipAuth(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + var v codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" @@ -51,7 +56,7 @@ func TestAccAWSCodePipelineWebhook_ipAuth(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineWebhookConfig_ipAuth(rName), + Config: testAccAWSCodePipelineWebhookConfig_ipAuth(rName, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -70,6 +75,8 @@ func TestAccAWSCodePipelineWebhook_ipAuth(t *testing.T) { } func TestAccAWSCodePipelineWebhook_unauthenticated(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + var v codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" @@ -80,7 +87,7 @@ func TestAccAWSCodePipelineWebhook_unauthenticated(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineWebhookConfig_unauthenticated(rName), + Config: testAccAWSCodePipelineWebhookConfig_unauthenticated(rName, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -97,6 +104,8 @@ func TestAccAWSCodePipelineWebhook_unauthenticated(t *testing.T) { } func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + var v1, v2, v3 codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" @@ -107,7 +116,7 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineWebhookConfigWithTags(rName, "tag1value", "tag2value"), + Config: testAccAWSCodePipelineWebhookConfigWithTags(rName, "tag1value", "tag2value", githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v1), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -117,7 +126,7 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { ), }, { - Config: testAccAWSCodePipelineWebhookConfigWithTags(rName, "tag1valueUpdate", "tag2valueUpdate"), + Config: testAccAWSCodePipelineWebhookConfigWithTags(rName, "tag1valueUpdate", "tag2valueUpdate", githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v2), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -138,7 +147,7 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCodePipelineWebhookConfig_basic(rName), + Config: testAccAWSCodePipelineWebhookConfig_basic(rName, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v3), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -155,6 +164,8 @@ func TestAccAWSCodePipelineWebhook_tags(t *testing.T) { } func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken(t *testing.T) { + githubToken := os.Getenv("GITHUB_TOKEN") + var v1, v2 codepipeline.ListWebhookItem rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_codepipeline_webhook.test" @@ -165,7 +176,7 @@ func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken CheckDestroy: testAccCheckAWSCodePipelineDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCodePipelineWebhookConfig_basic(rName), + Config: testAccAWSCodePipelineWebhookConfig_basic(rName, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v1), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -175,7 +186,7 @@ func TestAccAWSCodePipelineWebhook_UpdateAuthenticationConfiguration_SecretToken ), }, { - Config: testAccAWSCodePipelineWebhookConfig_secretTokenUpdated(rName), + Config: testAccAWSCodePipelineWebhookConfig_secretTokenUpdated(rName, githubToken), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCodePipelineWebhookExists(resourceName, &v2), resource.TestCheckResourceAttrSet(resourceName, "id"), @@ -219,8 +230,8 @@ func testAccCheckAWSCodePipelineWebhookExists(n string, webhook *codepipeline.Li } } -func testAccAWSCodePipelineWebhookConfig_basic(rName string) string { - return testAccAWSCodePipelineWebhookConfig_codePipeline(rName) + fmt.Sprintf(` +func testAccAWSCodePipelineWebhookConfig_basic(rName, githubToken string) string { + return testAccAWSCodePipelineWebhookConfig_codePipeline(rName, githubToken) + fmt.Sprintf(` resource "aws_codepipeline_webhook" "test" { name = %[1]q authentication = "GITHUB_HMAC" @@ -239,8 +250,8 @@ resource "aws_codepipeline_webhook" "test" { `, rName) } -func testAccAWSCodePipelineWebhookConfig_ipAuth(rName string) string { - return testAccAWSCodePipelineWebhookConfig_codePipeline(rName) + fmt.Sprintf(` +func testAccAWSCodePipelineWebhookConfig_ipAuth(rName, githubToken string) string { + return testAccAWSCodePipelineWebhookConfig_codePipeline(rName, githubToken) + fmt.Sprintf(` resource "aws_codepipeline_webhook" "test" { name = %[1]q authentication = "IP" @@ -259,8 +270,8 @@ resource "aws_codepipeline_webhook" "test" { `, rName) } -func testAccAWSCodePipelineWebhookConfig_unauthenticated(rName string) string { - return testAccAWSCodePipelineWebhookConfig_codePipeline(rName) + fmt.Sprintf(` +func testAccAWSCodePipelineWebhookConfig_unauthenticated(rName, githubToken string) string { + return testAccAWSCodePipelineWebhookConfig_codePipeline(rName, githubToken) + fmt.Sprintf(` resource "aws_codepipeline_webhook" "test" { name = %[1]q authentication = "UNAUTHENTICATED" @@ -275,8 +286,8 @@ resource "aws_codepipeline_webhook" "test" { `, rName) } -func testAccAWSCodePipelineWebhookConfigWithTags(rName, tag1, tag2 string) string { - return testAccAWSCodePipelineWebhookConfig_codePipeline(rName) + fmt.Sprintf(` +func testAccAWSCodePipelineWebhookConfigWithTags(rName, tag1, tag2, githubToken string) string { + return testAccAWSCodePipelineWebhookConfig_codePipeline(rName, githubToken) + fmt.Sprintf(` resource "aws_codepipeline_webhook" "test" { name = %[1]q authentication = "GITHUB_HMAC" @@ -301,8 +312,8 @@ resource "aws_codepipeline_webhook" "test" { `, rName, tag1, tag2) } -func testAccAWSCodePipelineWebhookConfig_secretTokenUpdated(rName string) string { - return testAccAWSCodePipelineWebhookConfig_codePipeline(rName) + fmt.Sprintf(` +func testAccAWSCodePipelineWebhookConfig_secretTokenUpdated(rName, githubToken string) string { + return testAccAWSCodePipelineWebhookConfig_codePipeline(rName, githubToken) + fmt.Sprintf(` resource "aws_codepipeline_webhook" "test" { name = %[1]q authentication = "GITHUB_HMAC" @@ -321,7 +332,7 @@ resource "aws_codepipeline_webhook" "test" { `, rName) } -func testAccAWSCodePipelineWebhookConfig_codePipeline(rName string) string { +func testAccAWSCodePipelineWebhookConfig_codePipeline(rName, githubToken string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q @@ -408,7 +419,8 @@ resource "aws_codepipeline" "test" { configuration = { Owner = "lifesum-terraform" Repo = "test" - Branch = "master" + Branch = "master" + OAuthToken = %[2]q } } } @@ -430,5 +442,5 @@ resource "aws_codepipeline" "test" { } } } -`, rName) +`, rName, githubToken) }