Skip to content

Commit d106f39

Browse files
feat: Implement github_repository_dependabot_security_updates resource (#1851)
* feat: Implement github_repository_dependabot_security_updates resource * Check return value of API call --------- Co-authored-by: Keegan Campbell <[email protected]>
1 parent 69e5243 commit d106f39

File tree

5 files changed

+351
-0
lines changed

5 files changed

+351
-0
lines changed

github/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ func Provider() terraform.ResourceProvider {
136136
"github_release": resourceGithubRelease(),
137137
"github_repository": resourceGithubRepository(),
138138
"github_repository_autolink_reference": resourceGithubRepositoryAutolinkReference(),
139+
"github_repository_dependabot_security_updates": resourceGithubRepositoryDependabotSecurityUpdates(),
139140
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
140141
"github_repository_collaborators": resourceGithubRepositoryCollaborators(),
141142
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package github
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
7+
)
8+
9+
func resourceGithubRepositoryDependabotSecurityUpdates() *schema.Resource {
10+
return &schema.Resource{
11+
Create: resourceGithubRepositoryDependabotSecurityUpdatesCreateOrUpdate,
12+
Read: resourceGithubRepositoryDependabotSecurityUpdatesRead,
13+
Update: resourceGithubRepositoryDependabotSecurityUpdatesCreateOrUpdate,
14+
Delete: resourceGithubRepositoryDependabotSecurityUpdatesDelete,
15+
Importer: &schema.ResourceImporter{
16+
State: resourceGithubRepositoryDependabotSecurityUpdatesImport,
17+
},
18+
19+
Schema: map[string]*schema.Schema{
20+
"repository": {
21+
Type: schema.TypeString,
22+
Required: true,
23+
ForceNew: true,
24+
Description: "The GitHub repository.",
25+
},
26+
"enabled": {
27+
Type: schema.TypeBool,
28+
Required: true,
29+
Description: "The state of the automated security fixes.",
30+
},
31+
},
32+
}
33+
}
34+
35+
func resourceGithubRepositoryDependabotSecurityUpdatesCreateOrUpdate(d *schema.ResourceData, meta interface{}) error {
36+
client := meta.(*Owner).v3client
37+
owner := meta.(*Owner).name
38+
repoName := d.Get("repository").(string)
39+
enabled := d.Get("enabled").(bool)
40+
41+
ctx := context.Background()
42+
var err error
43+
if enabled {
44+
_, err = client.Repositories.EnableAutomatedSecurityFixes(ctx, owner, repoName)
45+
} else {
46+
_, err = client.Repositories.DisableAutomatedSecurityFixes(ctx, owner, repoName)
47+
}
48+
49+
if err != nil {
50+
return err
51+
}
52+
d.SetId(repoName)
53+
return resourceGithubRepositoryDependabotSecurityUpdatesRead(d, meta)
54+
}
55+
56+
func resourceGithubRepositoryDependabotSecurityUpdatesRead(d *schema.ResourceData, meta interface{}) error {
57+
client := meta.(*Owner).v3client
58+
orgName := meta.(*Owner).name
59+
repoName := d.Get("repository").(string)
60+
61+
ctx := context.Background()
62+
63+
p, _, err := client.Repositories.GetAutomatedSecurityFixes(ctx, orgName, repoName)
64+
if err != nil {
65+
return err
66+
}
67+
d.Set("enabled", p.Enabled)
68+
69+
return nil
70+
}
71+
72+
func resourceGithubRepositoryDependabotSecurityUpdatesDelete(d *schema.ResourceData, meta interface{}) error {
73+
client := meta.(*Owner).v3client
74+
orgName := meta.(*Owner).name
75+
repoName := d.Get("repository").(string)
76+
77+
ctx := context.Background()
78+
79+
_, err := client.Repositories.DisableAutomatedSecurityFixes(ctx, orgName, repoName)
80+
if err != nil {
81+
return err
82+
}
83+
84+
return resourceGithubRepositoryDependabotSecurityUpdatesRead(d, meta)
85+
}
86+
87+
func resourceGithubRepositoryDependabotSecurityUpdatesImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
88+
repoName := d.Id()
89+
90+
d.Set("repository", repoName)
91+
92+
err := resourceGithubRepositoryDependabotSecurityUpdatesRead(d, meta)
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
return []*schema.ResourceData{d}, nil
98+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
10+
)
11+
12+
func TestAccGithubAutomatedSecurityFixes(t *testing.T) {
13+
14+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
15+
16+
t.Run("enables automated security fixes without error", func(t *testing.T) {
17+
18+
enabled := "enabled = false"
19+
updatedEnabled := "enabled = true"
20+
config := fmt.Sprintf(`
21+
22+
resource "github_repository" "test" {
23+
name = "tf-acc-test-%s"
24+
visibility = "private"
25+
auto_init = true
26+
vulnerability_alerts = true
27+
}
28+
29+
30+
resource "github_repository_dependabot_security_updates" "test" {
31+
repository = github_repository.test.id
32+
%s
33+
}
34+
`, randomID, enabled)
35+
36+
checks := map[string]resource.TestCheckFunc{
37+
"before": resource.ComposeTestCheckFunc(
38+
resource.TestCheckResourceAttr(
39+
"github_repository_dependabot_security_updates.test", "enabled",
40+
"false",
41+
),
42+
),
43+
"after": resource.ComposeTestCheckFunc(
44+
resource.TestCheckResourceAttr(
45+
"github_repository_dependabot_security_updates.test", "enabled",
46+
"true",
47+
),
48+
),
49+
}
50+
51+
testCase := func(t *testing.T, mode string) {
52+
resource.Test(t, resource.TestCase{
53+
PreCheck: func() { skipUnlessMode(t, mode) },
54+
Providers: testAccProviders,
55+
Steps: []resource.TestStep{
56+
{
57+
Config: config,
58+
Check: checks["before"],
59+
},
60+
{
61+
Config: strings.Replace(config,
62+
enabled,
63+
updatedEnabled, 1),
64+
Check: checks["after"],
65+
},
66+
},
67+
})
68+
}
69+
70+
t.Run("with an anonymous account", func(t *testing.T) {
71+
t.Skip("anonymous account not supported for this operation")
72+
})
73+
74+
t.Run("with an individual account", func(t *testing.T) {
75+
testCase(t, individual)
76+
})
77+
78+
t.Run("with an organization account", func(t *testing.T) {
79+
testCase(t, organization)
80+
})
81+
})
82+
83+
t.Run("disables automated security fixes without error", func(t *testing.T) {
84+
85+
enabled := "enabled = true"
86+
updatedEnabled := "enabled = false"
87+
88+
config := fmt.Sprintf(`
89+
90+
resource "github_repository" "test" {
91+
name = "tf-acc-test-%s"
92+
visibility = "private"
93+
auto_init = true
94+
vulnerability_alerts = true
95+
}
96+
97+
98+
resource "github_repository_dependabot_security_updates" "test" {
99+
repository = github_repository.test.id
100+
%s
101+
}
102+
`, randomID, enabled)
103+
104+
checks := map[string]resource.TestCheckFunc{
105+
"before": resource.ComposeTestCheckFunc(
106+
resource.TestCheckResourceAttr(
107+
"github_repository_dependabot_security_updates.test", "enabled",
108+
"true",
109+
),
110+
),
111+
"after": resource.ComposeTestCheckFunc(
112+
resource.TestCheckResourceAttr(
113+
"github_repository_dependabot_security_updates.test", "enabled",
114+
"false",
115+
),
116+
),
117+
}
118+
119+
testCase := func(t *testing.T, mode string) {
120+
resource.Test(t, resource.TestCase{
121+
PreCheck: func() { skipUnlessMode(t, mode) },
122+
Providers: testAccProviders,
123+
Steps: []resource.TestStep{
124+
{
125+
Config: config,
126+
Check: checks["before"],
127+
},
128+
{
129+
Config: strings.Replace(config,
130+
enabled,
131+
updatedEnabled, 1),
132+
Check: checks["after"],
133+
},
134+
},
135+
})
136+
}
137+
138+
t.Run("with an anonymous account", func(t *testing.T) {
139+
t.Skip("anonymous account not supported for this operation")
140+
})
141+
142+
t.Run("with an individual account", func(t *testing.T) {
143+
testCase(t, individual)
144+
})
145+
146+
t.Run("with an organization account", func(t *testing.T) {
147+
testCase(t, organization)
148+
})
149+
})
150+
151+
t.Run("imports automated security fixes without error", func(t *testing.T) {
152+
config := fmt.Sprintf(`
153+
resource "github_repository" "test" {
154+
name = "tf-acc-test-%s"
155+
vulnerability_alerts = true
156+
}
157+
158+
resource "github_repository_dependabot_security_updates" "test" {
159+
repository = github_repository.test.id
160+
enabled = false
161+
}
162+
`, randomID)
163+
164+
check := resource.ComposeTestCheckFunc(
165+
resource.TestCheckResourceAttrSet("github_repository_dependabot_security_updates.test", "repository"),
166+
resource.TestCheckResourceAttrSet("github_repository_dependabot_security_updates.test", "enabled"),
167+
resource.TestCheckResourceAttr("github_repository_dependabot_security_updates.test", "enabled", "false"),
168+
)
169+
170+
testCase := func(t *testing.T, mode string) {
171+
resource.Test(t, resource.TestCase{
172+
PreCheck: func() { skipUnlessMode(t, mode) },
173+
Providers: testAccProviders,
174+
Steps: []resource.TestStep{
175+
{
176+
Config: config,
177+
Check: check,
178+
},
179+
{
180+
ResourceName: "github_repository_dependabot_security_updates.test",
181+
ImportState: true,
182+
ImportStateVerify: true,
183+
},
184+
},
185+
})
186+
}
187+
188+
t.Run("with an anonymous account", func(t *testing.T) {
189+
t.Skip("anonymous account not supported for this operation")
190+
})
191+
192+
t.Run("with an individual account", func(t *testing.T) {
193+
testCase(t, individual)
194+
})
195+
196+
t.Run("with an organization account", func(t *testing.T) {
197+
testCase(t, organization)
198+
})
199+
})
200+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
layout: "github"
3+
page_title: "GitHub: github_repository_dependabot_security_updates"
4+
description: |-
5+
Manages automated security fixes for a single repository
6+
---
7+
8+
# github_repository_dependabot_security_updates
9+
10+
This resource allows you to manage dependabot automated security fixes for a single repository. See the
11+
[documentation](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates)
12+
for details of usage and how this will impact your repository
13+
14+
## Example Usage
15+
16+
```hcl
17+
resource "github_repository" "repo" {
18+
name = "my-repo"
19+
description = "GitHub repo managed by Terraform"
20+
21+
private = false
22+
23+
vulnerability_alerts = true
24+
}
25+
26+
27+
resource "github_repository_dependabot_security_updates" "example" {
28+
repository = github_repository.test.id
29+
enabled = true
30+
}
31+
```
32+
33+
## Argument Reference
34+
35+
The following arguments are supported:
36+
37+
* `repository` - (Required) The repository to manage.
38+
39+
* `enabled` - (Required) The state of the automated security fixes.
40+
41+
## Import
42+
43+
Automated security references can be imported using the `name` of the repository
44+
45+
### Import by name
46+
47+
```sh
48+
terraform import github_repository_dependabot_security_updates.example my-repo
49+
```

website/github.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@
298298
<li>
299299
<a href="/docs/providers/github/r/repository_autolink_reference.html">github_repository_autolink_reference</a>
300300
</li>
301+
<li>
302+
<a href="/docs/providers/github/r/repository_automated_security_fixes.html">github_repository_dependabot_security_updates</a>
303+
</li>
301304
<li>
302305
<a href="/docs/providers/github/r/repository_collaborator.html">github_repository_collaborator</a>
303306
</li>

0 commit comments

Comments
 (0)