Skip to content

Commit

Permalink
feat: Implement github_repository_dependabot_security_updates resource (
Browse files Browse the repository at this point in the history
#1851)

* feat: Implement github_repository_dependabot_security_updates resource

* Check return value of API call

---------

Co-authored-by: Keegan Campbell <[email protected]>
  • Loading branch information
grahamhar and kfcampbell authored Aug 24, 2023
1 parent 69e5243 commit d106f39
Show file tree
Hide file tree
Showing 5 changed files with 351 additions and 0 deletions.
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func Provider() terraform.ResourceProvider {
"github_release": resourceGithubRelease(),
"github_repository": resourceGithubRepository(),
"github_repository_autolink_reference": resourceGithubRepositoryAutolinkReference(),
"github_repository_dependabot_security_updates": resourceGithubRepositoryDependabotSecurityUpdates(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_collaborators": resourceGithubRepositoryCollaborators(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
Expand Down
98 changes: 98 additions & 0 deletions github/resource_github_repository_automated_security_fixes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package github

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceGithubRepositoryDependabotSecurityUpdates() *schema.Resource {
return &schema.Resource{
Create: resourceGithubRepositoryDependabotSecurityUpdatesCreateOrUpdate,
Read: resourceGithubRepositoryDependabotSecurityUpdatesRead,
Update: resourceGithubRepositoryDependabotSecurityUpdatesCreateOrUpdate,
Delete: resourceGithubRepositoryDependabotSecurityUpdatesDelete,
Importer: &schema.ResourceImporter{
State: resourceGithubRepositoryDependabotSecurityUpdatesImport,
},

Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The GitHub repository.",
},
"enabled": {
Type: schema.TypeBool,
Required: true,
Description: "The state of the automated security fixes.",
},
},
}
}

func resourceGithubRepositoryDependabotSecurityUpdatesCreateOrUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
owner := meta.(*Owner).name
repoName := d.Get("repository").(string)
enabled := d.Get("enabled").(bool)

ctx := context.Background()
var err error
if enabled {
_, err = client.Repositories.EnableAutomatedSecurityFixes(ctx, owner, repoName)
} else {
_, err = client.Repositories.DisableAutomatedSecurityFixes(ctx, owner, repoName)
}

if err != nil {
return err
}
d.SetId(repoName)
return resourceGithubRepositoryDependabotSecurityUpdatesRead(d, meta)
}

func resourceGithubRepositoryDependabotSecurityUpdatesRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
repoName := d.Get("repository").(string)

ctx := context.Background()

p, _, err := client.Repositories.GetAutomatedSecurityFixes(ctx, orgName, repoName)
if err != nil {
return err
}
d.Set("enabled", p.Enabled)

return nil
}

func resourceGithubRepositoryDependabotSecurityUpdatesDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
repoName := d.Get("repository").(string)

ctx := context.Background()

_, err := client.Repositories.DisableAutomatedSecurityFixes(ctx, orgName, repoName)
if err != nil {
return err
}

return resourceGithubRepositoryDependabotSecurityUpdatesRead(d, meta)
}

func resourceGithubRepositoryDependabotSecurityUpdatesImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
repoName := d.Id()

d.Set("repository", repoName)

err := resourceGithubRepositoryDependabotSecurityUpdatesRead(d, meta)
if err != nil {
return nil, err
}

return []*schema.ResourceData{d}, nil
}
200 changes: 200 additions & 0 deletions github/resource_github_repository_automated_security_fixes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package github

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccGithubAutomatedSecurityFixes(t *testing.T) {

randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

t.Run("enables automated security fixes without error", func(t *testing.T) {

enabled := "enabled = false"
updatedEnabled := "enabled = true"
config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
visibility = "private"
auto_init = true
vulnerability_alerts = true
}
resource "github_repository_dependabot_security_updates" "test" {
repository = github_repository.test.id
%s
}
`, randomID, enabled)

checks := map[string]resource.TestCheckFunc{
"before": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_repository_dependabot_security_updates.test", "enabled",
"false",
),
),
"after": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_repository_dependabot_security_updates.test", "enabled",
"true",
),
),
}

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: checks["before"],
},
{
Config: strings.Replace(config,
enabled,
updatedEnabled, 1),
Check: checks["after"],
},
},
})
}

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) {
testCase(t, individual)
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})

t.Run("disables automated security fixes without error", func(t *testing.T) {

enabled := "enabled = true"
updatedEnabled := "enabled = false"

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
visibility = "private"
auto_init = true
vulnerability_alerts = true
}
resource "github_repository_dependabot_security_updates" "test" {
repository = github_repository.test.id
%s
}
`, randomID, enabled)

checks := map[string]resource.TestCheckFunc{
"before": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_repository_dependabot_security_updates.test", "enabled",
"true",
),
),
"after": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_repository_dependabot_security_updates.test", "enabled",
"false",
),
),
}

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: checks["before"],
},
{
Config: strings.Replace(config,
enabled,
updatedEnabled, 1),
Check: checks["after"],
},
},
})
}

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) {
testCase(t, individual)
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})

t.Run("imports automated security fixes without error", func(t *testing.T) {
config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
vulnerability_alerts = true
}
resource "github_repository_dependabot_security_updates" "test" {
repository = github_repository.test.id
enabled = false
}
`, randomID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("github_repository_dependabot_security_updates.test", "repository"),
resource.TestCheckResourceAttrSet("github_repository_dependabot_security_updates.test", "enabled"),
resource.TestCheckResourceAttr("github_repository_dependabot_security_updates.test", "enabled", "false"),
)

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,
},
{
ResourceName: "github_repository_dependabot_security_updates.test",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

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) {
testCase(t, individual)
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})
}
49 changes: 49 additions & 0 deletions website/docs/r/repository_automated_security_fixes.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
layout: "github"
page_title: "GitHub: github_repository_dependabot_security_updates"
description: |-
Manages automated security fixes for a single repository
---

# github_repository_dependabot_security_updates

This resource allows you to manage dependabot automated security fixes for a single repository. See the
[documentation](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates)
for details of usage and how this will impact your repository

## Example Usage

```hcl
resource "github_repository" "repo" {
name = "my-repo"
description = "GitHub repo managed by Terraform"
private = false
vulnerability_alerts = true
}
resource "github_repository_dependabot_security_updates" "example" {
repository = github_repository.test.id
enabled = true
}
```

## Argument Reference

The following arguments are supported:

* `repository` - (Required) The repository to manage.

* `enabled` - (Required) The state of the automated security fixes.

## Import

Automated security references can be imported using the `name` of the repository

### Import by name

```sh
terraform import github_repository_dependabot_security_updates.example my-repo
```
3 changes: 3 additions & 0 deletions website/github.erb
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@
<li>
<a href="/docs/providers/github/r/repository_autolink_reference.html">github_repository_autolink_reference</a>
</li>
<li>
<a href="/docs/providers/github/r/repository_automated_security_fixes.html">github_repository_dependabot_security_updates</a>
</li>
<li>
<a href="/docs/providers/github/r/repository_collaborator.html">github_repository_collaborator</a>
</li>
Expand Down

0 comments on commit d106f39

Please sign in to comment.