From 410db7f2850d18c803810df8eeea92789fc46057 Mon Sep 17 00:00:00 2001 From: Brett Kuhlman Date: Mon, 26 Sep 2022 14:27:40 -0400 Subject: [PATCH 1/4] adding security_and_analysis block to repo resource --- github/resource_github_repository.go | 133 ++++++++++++++++++++++ github/resource_github_repository_test.go | 59 ++++++++++ website/docs/r/repository.html.markdown | 20 ++++ 3 files changed, 212 insertions(+) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 5cedfb9046..ffcb01aa77 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -54,6 +54,58 @@ func resourceGithubRepository() *schema.Resource { Computed: true, // is affected by "private" ValidateFunc: validation.StringInSlice([]string{"public", "private", "internal"}, false), }, + "security_and_analysis": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: "Security and analysis settings for the repository. To use this parameter you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "advanced_security": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"enabled", "disabled"}, false), + }, + }, + }, + }, + "secret_scanning": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"enabled", "disabled"}, false), + }, + }, + }, + }, /*TODO: SecretScanningPushProtection is not yet supported by the Go GitHub Client Library + "secret_scanning_push_protection": { + Type: schema.List, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"enabled", "disabled"}, false), + }, + }, + }, + },*/ + }, + }, + }, "has_issues": { Type: schema.TypeBool, Optional: true, @@ -417,6 +469,14 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er } } + securityAndAnalysis := expandSecurityAndAnalysis(d.Get("security_and_analysis").([]interface{})) + if securityAndAnalysis != nil { + _, _, err := client.Repositories.Edit(ctx, owner, repoName, securityAndAnalysis) + if err != nil { + return err + } + } + return resourceGithubRepositoryUpdate(d, meta) } @@ -512,6 +572,12 @@ func resourceGithubRepositoryRead(d *schema.ResourceData, meta interface{}) erro d.Set("vulnerability_alerts", vulnerabilityAlerts) } + securityAndAnalysis, _, err := client.Repositories.Edit(ctx, owner, repoName, &github.Repository{}) + if err != nil { + return fmt.Errorf("Error reading repository security and analysis settings: %v", err) + } + d.Set("security_and_analysis", flattenSecurityAndAnalysis(securityAndAnalysis.GetSecurityAndAnalysis())) + return nil } @@ -563,6 +629,27 @@ func resourceGithubRepositoryUpdate(d *schema.ResourceData, meta interface{}) er } } + if d.HasChange("security_and_analysis") && !d.IsNewResource() { + opts := expandSecurityAndAnalysis(d.Get("security_and_analysis").([]interface{})) + if opts != nil { + _, _, err := client.Repositories.Edit(ctx, owner, repoName, opts) + if err != nil { + return err + } + } else { // disable security and analysis + _, _, err := client.Repositories.Edit(ctx, owner, repoName, &github.Repository{ + SecurityAndAnalysis: &github.SecurityAndAnalysis{ + AdvancedSecurity: &github.AdvancedSecurity{ + Status: github.String("disabled")}, + SecretScanning: &github.SecretScanning{ + Status: github.String("disabled")}}, + }) + if err != nil { + return err + } + } + } + if d.HasChange("topics") { topics := repoReq.Topics _, _, err = client.Repositories.ReplaceAllTopics(ctx, owner, *repo.Name, topics) @@ -715,3 +802,49 @@ func flattenPages(pages *github.Pages) []interface{} { return []interface{}{pagesMap} } + +func flattenSecurityAndAnalysis(securityAndAnalysis *github.SecurityAndAnalysis) []interface{} { + if securityAndAnalysis == nil { + return []interface{}{} + } + + advancedSecurityMap := make(map[string]interface{}) + advancedSecurityMap["status"] = securityAndAnalysis.GetAdvancedSecurity().GetStatus() + secretScanningMap := make(map[string]interface{}) + secretScanningMap["status"] = securityAndAnalysis.GetSecretScanning().GetStatus() + //TODO: SecretScanningPushProtection is not yet supported by the Go GitHub Client Library + //secretScanningPushProtectionMap := make(map[string]interface{}) + //secretScanningPushProtectionMap["status"] = securityAndAnalysis.GetSecretScanningPushProtection().GetStatus() + + securityAndAnalysisMap := make(map[string]interface{}) + securityAndAnalysisMap["advanced_security"] = []interface{}{advancedSecurityMap} + securityAndAnalysisMap["secret_scanning"] = []interface{}{secretScanningMap} + + return []interface{}{securityAndAnalysisMap} +} + +func expandSecurityAndAnalysis(input []interface{}) *github.Repository { + if len(input) == 0 || input[0] == nil { + return nil + } + + securityAndAnalysis := input[0].(map[string]interface{}) + update := &github.SecurityAndAnalysis{} + + advancedSecurity := securityAndAnalysis["advanced_security"].([]interface{})[0].(map[string]interface{}) + update.AdvancedSecurity = &github.AdvancedSecurity{ + Status: github.String(advancedSecurity["status"].(string)), + } + + secretScanning := securityAndAnalysis["secret_scanning"].([]interface{})[0].(map[string]interface{}) + update.SecretScanning = &github.SecretScanning{ + Status: github.String(secretScanning["status"].(string)), + } + //TODO: SecretScanningPushProtection is not yet supported by the Go GitHub Client Library + //secretScanningPushProtection := securityAndAnalysis["secret_scanning_push_protection"].([]interface{})[0].(map[string]interface{}) + //update.SecretScanningPushProtection = &github.SecretScanningPushProtection{ + // Status: github.String(secretScanningPushProtection["status"].(string)), + //} + + return &github.Repository{SecurityAndAnalysis: update} +} diff --git a/github/resource_github_repository_test.go b/github/resource_github_repository_test.go index 3d9144e258..a6c73b220e 100644 --- a/github/resource_github_repository_test.go +++ b/github/resource_github_repository_test.go @@ -809,6 +809,65 @@ func TestAccGithubRepositoryPages(t *testing.T) { } +func TestAccGithubRepositorySecurity(t *testing.T) { + + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + + t.Run("manages the security feature for a repository", func(t *testing.T) { + + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "tf-acc-%s" + description = "A repository created by Terraform to test security features" + visibility = "internal" + security_and_analysis { + advanced_security { + status = "enabled" + } + secret_scanning { + status = "enabled" + } + } + } + `, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "security_and_analysis.0.advanced_security.0.status", + "enabled", + ), + resource.TestCheckResourceAttr( + "github_repository.test", "security_and_analysis.0.secret_scanning.0.status", + "enabled", + ), + ) + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + + t.Run("with an individual account", func(t *testing.T) { + t.Skip("individual account not supported for this operation") + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + }) +} + func TestAccGithubRepositoryVisibility(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index b816fcf5f0..1fd6cac26d 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -106,6 +106,8 @@ initial repository creation and create the target branch inside of the repositor * `pages` - (Optional) The repository's GitHub Pages configuration. See [GitHub Pages Configuration](#github-pages-configuration) below for details. +* `security_and_analysis` - (Optional) The repository's [security and analysis](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository) configuration. See [Security and Analysis Configuration](#security-and-analysis-configuration) below for details. + * `topics` - (Optional) The list of topics of the repository. * `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details. @@ -132,6 +134,24 @@ The `source` block supports the following: * `path` - (Optional) The repository directory from which the site publishes (Default: `/`). +### Security and Analysis Configuration + +The `security_and_analysis` block supports the following: + +* `advanced_security` - (Optional) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. + +* `secret_scanning` - (Optional) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. + +#### Advanced Security Configuration #### + +The `advanced_security` block supports the following: + +* `status` - (Optional) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. + +#### Secret Scanning Configuration #### + +* `status` - (Optional) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. + ### Template Repositories `template` supports the following arguments: From 1639e4f6411ad454ffd9f9a1adf8a7cf8123f15c Mon Sep 17 00:00:00 2001 From: Brett Kuhlman Date: Fri, 28 Oct 2022 07:55:18 -0400 Subject: [PATCH 2/4] Adding SecretScanningPushProtection fields. --- github/resource_github_repository.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index ffcb01aa77..09a9ae3f8d 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -88,9 +88,9 @@ func resourceGithubRepository() *schema.Resource { }, }, }, - }, /*TODO: SecretScanningPushProtection is not yet supported by the Go GitHub Client Library + }, "secret_scanning_push_protection": { - Type: schema.List, + Type: schema.TypeList, Required: true, MaxItems: 1, Elem: &schema.Resource{ @@ -102,7 +102,7 @@ func resourceGithubRepository() *schema.Resource { }, }, }, - },*/ + }, }, }, }, @@ -642,6 +642,8 @@ func resourceGithubRepositoryUpdate(d *schema.ResourceData, meta interface{}) er AdvancedSecurity: &github.AdvancedSecurity{ Status: github.String("disabled")}, SecretScanning: &github.SecretScanning{ + Status: github.String("disabled")}, + SecretScanningPushProtection: &github.SecretScanningPushProtection{ Status: github.String("disabled")}}, }) if err != nil { @@ -812,9 +814,8 @@ func flattenSecurityAndAnalysis(securityAndAnalysis *github.SecurityAndAnalysis) advancedSecurityMap["status"] = securityAndAnalysis.GetAdvancedSecurity().GetStatus() secretScanningMap := make(map[string]interface{}) secretScanningMap["status"] = securityAndAnalysis.GetSecretScanning().GetStatus() - //TODO: SecretScanningPushProtection is not yet supported by the Go GitHub Client Library - //secretScanningPushProtectionMap := make(map[string]interface{}) - //secretScanningPushProtectionMap["status"] = securityAndAnalysis.GetSecretScanningPushProtection().GetStatus() + secretScanningPushProtectionMap := make(map[string]interface{}) + secretScanningPushProtectionMap["status"] = securityAndAnalysis.GetSecretScanningPushProtection().GetStatus() securityAndAnalysisMap := make(map[string]interface{}) securityAndAnalysisMap["advanced_security"] = []interface{}{advancedSecurityMap} @@ -840,11 +841,10 @@ func expandSecurityAndAnalysis(input []interface{}) *github.Repository { update.SecretScanning = &github.SecretScanning{ Status: github.String(secretScanning["status"].(string)), } - //TODO: SecretScanningPushProtection is not yet supported by the Go GitHub Client Library - //secretScanningPushProtection := securityAndAnalysis["secret_scanning_push_protection"].([]interface{})[0].(map[string]interface{}) - //update.SecretScanningPushProtection = &github.SecretScanningPushProtection{ - // Status: github.String(secretScanningPushProtection["status"].(string)), - //} + secretScanningPushProtection := securityAndAnalysis["secret_scanning_push_protection"].([]interface{})[0].(map[string]interface{}) + update.SecretScanningPushProtection = &github.SecretScanningPushProtection{ + Status: github.String(secretScanningPushProtection["status"].(string)), + } return &github.Repository{SecurityAndAnalysis: update} } From 91444b30377b7ccea339343a5638b557ad05827c Mon Sep 17 00:00:00 2001 From: Brett Kuhlman Date: Fri, 28 Oct 2022 08:03:01 -0400 Subject: [PATCH 3/4] updating docs to inclued secret_scanning_push_protection field --- website/docs/r/repository.html.markdown | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index 1fd6cac26d..51980679b8 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -138,19 +138,25 @@ The `source` block supports the following: The `security_and_analysis` block supports the following: -* `advanced_security` - (Optional) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. +* `advanced_security` - (Required) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. -* `secret_scanning` - (Optional) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. +* `secret_scanning` - (Required) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. + +* `secret_scanning_push_protection` - (Required) The secret scanning push protection configuration for the repository. See [Secret Scanning Push Protection Configuration](#secret-scanning-push-protection-configuration) below for details. #### Advanced Security Configuration #### The `advanced_security` block supports the following: -* `status` - (Optional) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. +* `status` - (Required) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. #### Secret Scanning Configuration #### -* `status` - (Optional) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. +* `status` - (Required) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. + +#### Secret Scanning Push Protection Configuration #### + +* `status` - (Required) Set to `enabled` to enable secret scanning push protection on the repository. Can be `enabled` or `disabled`. ### Template Repositories From 72cab5da5a7cecaff556485efb484f6a7bee04c2 Mon Sep 17 00:00:00 2001 From: Brett Kuhlman Date: Tue, 1 Nov 2022 15:59:47 -0400 Subject: [PATCH 4/4] updating repo tests for security --- github/resource_github_repository.go | 4 ++++ github/resource_github_repository_test.go | 2 ++ 2 files changed, 6 insertions(+) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 09a9ae3f8d..2188e66afa 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -812,14 +812,17 @@ func flattenSecurityAndAnalysis(securityAndAnalysis *github.SecurityAndAnalysis) advancedSecurityMap := make(map[string]interface{}) advancedSecurityMap["status"] = securityAndAnalysis.GetAdvancedSecurity().GetStatus() + secretScanningMap := make(map[string]interface{}) secretScanningMap["status"] = securityAndAnalysis.GetSecretScanning().GetStatus() + secretScanningPushProtectionMap := make(map[string]interface{}) secretScanningPushProtectionMap["status"] = securityAndAnalysis.GetSecretScanningPushProtection().GetStatus() securityAndAnalysisMap := make(map[string]interface{}) securityAndAnalysisMap["advanced_security"] = []interface{}{advancedSecurityMap} securityAndAnalysisMap["secret_scanning"] = []interface{}{secretScanningMap} + securityAndAnalysisMap["secret_scanning_push_protection"] = []interface{}{secretScanningPushProtectionMap} return []interface{}{securityAndAnalysisMap} } @@ -841,6 +844,7 @@ func expandSecurityAndAnalysis(input []interface{}) *github.Repository { update.SecretScanning = &github.SecretScanning{ Status: github.String(secretScanning["status"].(string)), } + secretScanningPushProtection := securityAndAnalysis["secret_scanning_push_protection"].([]interface{})[0].(map[string]interface{}) update.SecretScanningPushProtection = &github.SecretScanningPushProtection{ Status: github.String(secretScanningPushProtection["status"].(string)), diff --git a/github/resource_github_repository_test.go b/github/resource_github_repository_test.go index a6c73b220e..4528e681f5 100644 --- a/github/resource_github_repository_test.go +++ b/github/resource_github_repository_test.go @@ -827,6 +827,8 @@ func TestAccGithubRepositorySecurity(t *testing.T) { secret_scanning { status = "enabled" } + secret_scanning_push_protection { + status = "enabled" } } `, randomID)