Skip to content

Commit

Permalink
feat: Ability to Manage Codespaces Secrets (#1729)
Browse files Browse the repository at this point in the history
* add github_codespaces_secret

* use repository as repoName

* add github_codespaces_organization_secret

* add github_codespaces_user_secret

* fix version

* add docs

* fix id conversion

* add codespaces_*public_key data source

* switch back to use of name/full_name

* update org test

* update repo test

* remove user secret visibiltiy prop & update tests

---------

Co-authored-by: Keegan Campbell <me@kfcampbell.com>
  • Loading branch information
KenSpur and kfcampbell authored Jun 27, 2023
1 parent 37783e2 commit 498907b
Show file tree
Hide file tree
Showing 29 changed files with 2,333 additions and 0 deletions.
47 changes: 47 additions & 0 deletions github/data_source_github_codespaces_organization_public_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package github

import (
"context"

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

func dataSourceGithubCodespacesOrganizationPublicKey() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubCodespacesOrganizationPublicKeyRead,

Schema: map[string]*schema.Schema{
"key_id": {
Type: schema.TypeString,
Computed: true,
},
"key": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceGithubCodespacesOrganizationPublicKeyRead(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}

client := meta.(*Owner).v3client
owner := meta.(*Owner).name

ctx := context.Background()

publicKey, _, err := client.Codespaces.GetOrgPublicKey(ctx, owner)
if err != nil {
return err
}

d.SetId(publicKey.GetKeyID())
d.Set("key_id", publicKey.GetKeyID())
d.Set("key", publicKey.GetKey())

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package github

import (
"testing"

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

func TestAccGithubCodespacesOrganizationPublicKeyDataSource(t *testing.T) {

t.Run("queries an organization public key without error", func(t *testing.T) {

config := `
data "github_codespaces_organization_public_key" "test" {}
`

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"data.github_codespaces_organization_public_key.test", "key",
),
)

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

})
}
78 changes: 78 additions & 0 deletions github/data_source_github_codespaces_organization_secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package github

import (
"context"

"github.com/google/go-github/v53/github"

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

func dataSourceGithubCodespacesOrganizationSecrets() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubCodespacesOrganizationSecretsRead,

Schema: map[string]*schema.Schema{
"secrets": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
},
"visibility": {
Type: schema.TypeString,
Computed: true,
},
"created_at": {
Type: schema.TypeString,
Computed: true,
},
"updated_at": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
}
}

func dataSourceGithubCodespacesOrganizationSecretsRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Owner).v3client
owner := meta.(*Owner).name

options := github.ListOptions{
PerPage: 100,
}

var all_secrets []map[string]string
for {
secrets, resp, err := client.Codespaces.ListOrgSecrets(context.TODO(), owner, &options)
if err != nil {
return err
}
for _, secret := range secrets.Secrets {
new_secret := map[string]string{
"name": secret.Name,
"visibility": secret.Visibility,
"created_at": secret.CreatedAt.String(),
"updated_at": secret.UpdatedAt.String(),
}
all_secrets = append(all_secrets, new_secret)

}
if resp.NextPage == 0 {
break
}
options.Page = resp.NextPage
}

d.SetId(owner)
d.Set("secrets", all_secrets)

return nil
}
59 changes: 59 additions & 0 deletions github/data_source_github_codespaces_organization_secrets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package github

import (
"fmt"
"strings"
"testing"

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

func TestAccGithubCodespacesOrganizationSecretsDataSource(t *testing.T) {

t.Run("queries organization codespaces secrets from a repository", func(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

config := fmt.Sprintf(`
resource "github_codespaces_organization_secret" "test" {
secret_name = "org_cs_secret_1_%s"
plaintext_value = "foo"
visibility = "private"
}
`, randomID)

config2 := config + `
data "github_codespaces_organization_secrets" "test" {
}
`

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.github_codespaces_organization_secrets.test", "secrets.#", "1"),
resource.TestCheckResourceAttr("data.github_codespaces_organization_secrets.test", "secrets.0.name", strings.ToUpper(fmt.Sprintf("ORG_CS_SECRET_1_%s", randomID))),
resource.TestCheckResourceAttr("data.github_codespaces_organization_secrets.test", "secrets.0.visibility", "private"),
resource.TestCheckResourceAttrSet("data.github_codespaces_organization_secrets.test", "secrets.0.created_at"),
resource.TestCheckResourceAttrSet("data.github_codespaces_organization_secrets.test", "secrets.0.updated_at"),
)

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: resource.ComposeTestCheckFunc(),
},
{
Config: config2,
Check: check,
},
},
})
}

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})
}
49 changes: 49 additions & 0 deletions github/data_source_github_codespaces_public_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package github

import (
"context"
"log"

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

func dataSourceGithubCodespacesPublicKey() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubCodespacesPublicKeyRead,

Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
},
"key_id": {
Type: schema.TypeString,
Computed: true,
},
"key": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceGithubCodespacesPublicKeyRead(d *schema.ResourceData, meta interface{}) error {
repository := d.Get("repository").(string)
owner := meta.(*Owner).name
log.Printf("[INFO] Refreshing GitHub Codespaces Public Key from: %s/%s", owner, repository)

client := meta.(*Owner).v3client
ctx := context.Background()

publicKey, _, err := client.Codespaces.GetRepoPublicKey(ctx, owner, repository)
if err != nil {
return err
}

d.SetId(publicKey.GetKeyID())
d.Set("key_id", publicKey.GetKeyID())
d.Set("key", publicKey.GetKey())

return nil
}
60 changes: 60 additions & 0 deletions github/data_source_github_codespaces_public_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package github

import (
"fmt"
"testing"

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

func TestAccGithubCodespacesPublicKeyDataSource(t *testing.T) {

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

t.Run("queries a repository public key without error", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%[1]s"
auto_init = true
}
data "github_codespaces_public_key" "test" {
repository = github_repository.test.id
}
`, randomID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"data.github_codespaces_public_key.test", "key",
),
)

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

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

})
}
Loading

0 comments on commit 498907b

Please sign in to comment.