Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Adding security_and_analysis block to github_repository resource. closes#1104 #1304

Merged
merged 4 commits into from Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
137 changes: 137 additions & 0 deletions github/resource_github_repository.go
Expand Up @@ -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),
},
},
},
},
"secret_scanning_push_protection": {
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),
},
},
},
},
},
},
},
"has_issues": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -563,6 +629,29 @@ 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")},
SecretScanningPushProtection: &github.SecretScanningPushProtection{
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)
Expand Down Expand Up @@ -715,3 +804,51 @@ 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()

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}
}

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)),
}

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}
}
61 changes: 61 additions & 0 deletions github/resource_github_repository_test.go
Expand Up @@ -809,6 +809,67 @@ 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"
}
secret_scanning_push_protection {
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)
Expand Down
26 changes: 26 additions & 0 deletions website/docs/r/repository.html.markdown
Expand Up @@ -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.
Expand All @@ -132,6 +134,30 @@ 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` - (Required) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-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` - (Required) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`.

#### Secret Scanning Configuration ####

* `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

`template` supports the following arguments:
Expand Down