Skip to content

Adding github_enterprise_ip_allow_list_entry resource #2649

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ func Provider() *schema.Provider {
"github_user_ssh_key": resourceGithubUserSshKey(),
"github_enterprise_organization": resourceGithubEnterpriseOrganization(),
"github_enterprise_actions_runner_group": resourceGithubActionsEnterpriseRunnerGroup(),
"github_enterprise_ip_allow_list_entry": resourceGithubEnterpriseIpAllowListEntry(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
218 changes: 218 additions & 0 deletions github/resource_github_enterprise_ip_allow_list_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package github

import (
"context"
"log"
"strings"

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

func resourceGithubEnterpriseIpAllowListEntry() *schema.Resource {
return &schema.Resource{
Create: resourceGithubEnterpriseIpAllowListEntryCreate,
Read: resourceGithubEnterpriseIpAllowListEntryRead,
Update: resourceGithubEnterpriseIpAllowListEntryUpdate,
Delete: resourceGithubEnterpriseIpAllowListEntryDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"enterprise_slug": {
Type: schema.TypeString,
Required: true,
Description: "The slug of the enterprise to apply the IP allow list entry to.",
},
"ip": {
Type: schema.TypeString,
Required: true,
Description: "An IP address or range of IP addresses in CIDR notation.",
},
"name": {
Type: schema.TypeString,
Optional: true,
Description: "An optional name for the IP allow list entry.",
},
"is_active": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Whether the entry is currently active.",
},
},
}
}

func resourceGithubEnterpriseIpAllowListEntryCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v4client
ctx := context.WithValue(context.Background(), ctxId, d.Id())

// First, get the enterprise ID as we need it for the mutation
enterpriseSlug := d.Get("enterprise_slug").(string)
enterpriseID, err := getEnterpriseID(ctx, client, enterpriseSlug)
if err != nil {
return err
}

// Then create the IP allow list entry
var mutation struct {
CreateIpAllowListEntry struct {
IpAllowListEntry struct {
ID githubv4.String
AllowListValue githubv4.String
Name githubv4.String
IsActive githubv4.Boolean
CreatedAt githubv4.String
UpdatedAt githubv4.String
}
} `graphql:"createIpAllowListEntry(input: $input)"`
}

name := d.Get("name").(string)
input := githubv4.CreateIpAllowListEntryInput{
OwnerID: githubv4.ID(enterpriseID),
AllowListValue: githubv4.String(d.Get("ip").(string)),
IsActive: githubv4.Boolean(d.Get("is_active").(bool)),
}

if name != "" {
input.Name = githubv4.NewString(githubv4.String(name))
}

err = client.Mutate(ctx, &mutation, input, nil)
if err != nil {
return err
}

d.SetId(string(mutation.CreateIpAllowListEntry.IpAllowListEntry.ID))

return resourceGithubEnterpriseIpAllowListEntryRead(d, meta)
}

func resourceGithubEnterpriseIpAllowListEntryRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v4client
ctx := context.WithValue(context.Background(), ctxId, d.Id())

var query struct {
Node struct {
IpAllowListEntry struct {
ID githubv4.String
AllowListValue githubv4.String
Name githubv4.String
IsActive githubv4.Boolean
CreatedAt githubv4.String
UpdatedAt githubv4.String
Owner struct {
Enterprise struct {
Slug githubv4.String
} `graphql:"... on Enterprise"`
}
} `graphql:"... on IpAllowListEntry"`
} `graphql:"node(id: $id)"`
}

variables := map[string]interface{}{
"id": githubv4.ID(d.Id()),
}

err := client.Query(ctx, &query, variables)
if err != nil {
if strings.Contains(err.Error(), "Could not resolve to a node with the global id") {
log.Printf("[INFO] Removing IP allow list entry (%s) from state because it no longer exists in GitHub", d.Id())
d.SetId("")
return nil
}
return err
}

entry := query.Node.IpAllowListEntry

d.Set("ip", entry.AllowListValue)
d.Set("name", entry.Name)
d.Set("is_active", entry.IsActive)
d.Set("created_at", entry.CreatedAt)
d.Set("updated_at", entry.UpdatedAt)
d.Set("enterprise_slug", entry.Owner.Enterprise.Slug)

return nil
}

func resourceGithubEnterpriseIpAllowListEntryUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v4client
ctx := context.WithValue(context.Background(), ctxId, d.Id())

var mutation struct {
UpdateIpAllowListEntry struct {
IpAllowListEntry struct {
ID githubv4.String
AllowListValue githubv4.String
Name githubv4.String
IsActive githubv4.Boolean
UpdatedAt githubv4.String
}
} `graphql:"updateIpAllowListEntry(input: $input)"`
}

name := d.Get("name").(string)
input := githubv4.UpdateIpAllowListEntryInput{
IPAllowListEntryID: githubv4.ID(d.Id()),
AllowListValue: githubv4.String(d.Get("ip").(string)),
IsActive: githubv4.Boolean(d.Get("is_active").(bool)),
}

if name != "" {
input.Name = githubv4.NewString(githubv4.String(name))
}

err := client.Mutate(ctx, &mutation, input, nil)
if err != nil {
return err
}

return resourceGithubEnterpriseIpAllowListEntryRead(d, meta)
}

func resourceGithubEnterpriseIpAllowListEntryDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v4client
ctx := context.WithValue(context.Background(), ctxId, d.Id())

var mutation struct {
DeleteIpAllowListEntry struct {
ClientMutationID githubv4.String
} `graphql:"deleteIpAllowListEntry(input: $input)"`
}

input := githubv4.DeleteIpAllowListEntryInput{
IPAllowListEntryID: githubv4.ID(d.Id()),
}

err := client.Mutate(ctx, &mutation, input, nil)
if err != nil {
return err
}

d.SetId("")
return nil
}

// Helper function to get Enterprise ID from slug
func getEnterpriseID(ctx context.Context, client *githubv4.Client, enterpriseSlug string) (string, error) {
var query struct {
Enterprise struct {
ID githubv4.ID
} `graphql:"enterprise(slug: $slug)"`
}

variables := map[string]interface{}{
"slug": githubv4.String(enterpriseSlug),
}

err := client.Query(ctx, &query, variables)
if err != nil {
return "", err
}

return query.Enterprise.ID.(string), nil
}
101 changes: 101 additions & 0 deletions github/resource_github_enterprise_ip_allow_list_entry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package github

import (
"fmt"
"testing"

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

func TestAccGithubEnterpriseIpAllowListEntry_basic(t *testing.T) {
t.Skip("Acceptance test requires a real GitHub Enterprise environment")

resourceName := "github_enterprise_ip_allow_list_entry.test"
enterpriseSlug := "test-enterprise"
ip := "192.168.1.0/24"
name := "Test Entry"
isActive := true

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckEnterprise(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccGithubEnterpriseIpAllowListEntryConfig(enterpriseSlug, ip, name, isActive),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "enterprise_slug", enterpriseSlug),
resource.TestCheckResourceAttr(resourceName, "ip", ip),
resource.TestCheckResourceAttr(resourceName, "name", name),
resource.TestCheckResourceAttr(resourceName, "is_active", fmt.Sprintf("%t", isActive)),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccGithubEnterpriseIpAllowListEntry_update(t *testing.T) {
t.Skip("Acceptance test requires a real GitHub Enterprise environment")

resourceName := "github_enterprise_ip_allow_list_entry.test"
enterpriseSlug := "test-enterprise"
ip := "192.168.1.0/24"
name := "Test Entry"
isActive := true

updatedIP := "10.0.0.0/16"
updatedName := "Updated Entry"
updatedIsActive := false

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckEnterprise(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccGithubEnterpriseIpAllowListEntryConfig(enterpriseSlug, ip, name, isActive),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "enterprise_slug", enterpriseSlug),
resource.TestCheckResourceAttr(resourceName, "ip", ip),
resource.TestCheckResourceAttr(resourceName, "name", name),
resource.TestCheckResourceAttr(resourceName, "is_active", fmt.Sprintf("%t", isActive)),
),
},
{
Config: testAccGithubEnterpriseIpAllowListEntryConfig(enterpriseSlug, updatedIP, updatedName, updatedIsActive),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "enterprise_slug", enterpriseSlug),
resource.TestCheckResourceAttr(resourceName, "ip", updatedIP),
resource.TestCheckResourceAttr(resourceName, "name", updatedName),
resource.TestCheckResourceAttr(resourceName, "is_active", fmt.Sprintf("%t", updatedIsActive)),
),
},
},
})
}

func testAccGithubEnterpriseIpAllowListEntryConfig(enterpriseSlug, ip, name string, isActive bool) string {
return fmt.Sprintf(`
resource "github_enterprise_ip_allow_list_entry" "test" {
enterprise_slug = "%s"
ip = "%s"
name = "%s"
is_active = %t
}
`, enterpriseSlug, ip, name, isActive)
}

func testAccPreCheckEnterprise(t *testing.T) {
if v := testAccProvider.Meta().(*Owner).name; v == "" {
t.Fatal("The GITHUB_ENTERPRISE_SLUG environment variable must be set for enterprise tests")
}
}
38 changes: 38 additions & 0 deletions website/docs/r/enterprise_ip_allow_list_entry.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
layout: "github"
page_title: "GitHub: github_enterprise_ip_allow_list_entry"
description: |-
Creates and manages IP allow list entries within a GitHub Enterprise
---

# github_enterprise_ip_allow_list_entry

This resource allows you to create and manage IP allow list entries for a GitHub Enterprise account. IP allow list entries define IP addresses or ranges that are permitted to access private resources in the enterprise.

## Example Usage

```hcl
resource "github_enterprise_ip_allow_list_entry" "test" {
enterprise_slug = "my-enterprise"
ip = "192.168.1.0/20"
name = "My IP Range Name"
is_active = true
}
```

## Argument Reference

The following arguments are supported:

* `enterprise_slug` - (Required) The slug of the enterprise.
* `ip` - (Required) An IP address or range of IP addresses in CIDR notation.
* `name` - (Optional) A descriptive name for the IP allow list entry.
* `is_active` - (Optional) Whether the entry is currently active. Default: true.

## Import

This resource can be imported using the ID of the IP allow list entry:

```bash
$ terraform import github_enterprise_ip_allow_list_entry.test IALE_kwHOC1234567890a
```
Loading