Skip to content

Commit

Permalink
Adding in github_actions_organization_secret resource (integrations#584)
Browse files Browse the repository at this point in the history
Signed-off-by: Jacob Foard <[email protected]>

fixing github_actions_secret created/updated timestamp

Signed-off-by: Jacob Foard <[email protected]>

docs, adding repo_id attribute for repository

Signed-off-by: Jacob Foard <[email protected]>

s/orginization/organization/

Signed-off-by: Jacob Foard <[email protected]>

rename file, add in require param to tests

Signed-off-by: Jacob Foard <[email protected]>

Fixing test copy pasta

Signed-off-by: Jacob Foard <[email protected]>
  • Loading branch information
jacobfoard authored Nov 23, 2020
1 parent 38d9108 commit 2ce7092
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 28 deletions.
5 changes: 5 additions & 0 deletions github/data_source_github_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func dataSourceGithubRepository() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"repo_id": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -158,6 +162,7 @@ func dataSourceGithubRepositoryRead(d *schema.ResourceData, meta interface{}) er
d.Set("http_clone_url", repo.GetCloneURL())
d.Set("archived", repo.GetArchived())
d.Set("node_id", repo.GetNodeID())
d.Set("repo_id", repo.GetID())

err = d.Set("topics", flattenStringList(repo.Topics))
if err != nil {
Expand Down
46 changes: 23 additions & 23 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,29 @@ func Provider() terraform.ResourceProvider {
},

ResourcesMap: map[string]*schema.Resource{
"github_actions_secret": resourceGithubActionsSecret(),
"github_branch": resourceGithubBranch(),
"github_branch_protection": resourceGithubBranchProtection(),
"github_issue_label": resourceGithubIssueLabel(),
"github_membership": resourceGithubMembership(),
"github_organization_block": resourceOrganizationBlock(),
"github_organization_project": resourceGithubOrganizationProject(),
"github_organization_webhook": resourceGithubOrganizationWebhook(),
"github_project_column": resourceGithubProjectColumn(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
"github_repository_file": resourceGithubRepositoryFile(),
"github_repository_project": resourceGithubRepositoryProject(),
"github_repository_webhook": resourceGithubRepositoryWebhook(),
"github_repository": resourceGithubRepository(),
"github_team_membership": resourceGithubTeamMembership(),
"github_team_repository": resourceGithubTeamRepository(),
"github_team_sync_group_mapping": resourceGithubTeamSyncGroupMapping(),
"github_team": resourceGithubTeam(),
"github_user_gpg_key": resourceGithubUserGpgKey(),
"github_user_invitation_accepter": resourceGithubUserInvitationAccepter(),
"github_user_ssh_key": resourceGithubUserSshKey(),
"github_actions_organization_secret": resourceGithubActionsOrganizationSecret(),
"github_actions_secret": resourceGithubActionsSecret(),
"github_branch": resourceGithubBranch(),
"github_branch_protection": resourceGithubBranchProtection(),
"github_issue_label": resourceGithubIssueLabel(),
"github_membership": resourceGithubMembership(),
"github_organization_block": resourceOrganizationBlock(),
"github_organization_project": resourceGithubOrganizationProject(),
"github_organization_webhook": resourceGithubOrganizationWebhook(),
"github_project_column": resourceGithubProjectColumn(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
"github_repository_file": resourceGithubRepositoryFile(),
"github_repository_project": resourceGithubRepositoryProject(),
"github_repository_webhook": resourceGithubRepositoryWebhook(),
"github_repository": resourceGithubRepository(),
"github_team_membership": resourceGithubTeamMembership(),
"github_team_repository": resourceGithubTeamRepository(),
"github_team_sync_group_mapping": resourceGithubTeamSyncGroupMapping(),
"github_team": resourceGithubTeam(),
"github_user_gpg_key": resourceGithubUserGpgKey(),
"github_user_invitation_accepter": resourceGithubUserInvitationAccepter(),
"github_user_ssh_key": resourceGithubUserSshKey(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down Expand Up @@ -107,7 +108,6 @@ func init() {

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
return func(d *schema.ResourceData) (interface{}, error) {

anonymous := true
if d.Get("token").(string) != "" {
anonymous = false
Expand Down
159 changes: 159 additions & 0 deletions github/resource_github_actions_organization_secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package github

import (
"context"
"encoding/base64"
"fmt"
"log"
"net/http"

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

func resourceGithubActionsOrganizationSecret() *schema.Resource {
return &schema.Resource{
Create: resourceGithubActionsOrganizationSecretCreateOrUpdate,
Read: resourceGithubActionsOrganizationSecretRead,
Update: resourceGithubActionsOrganizationSecretCreateOrUpdate,
Delete: resourceGithubActionsOrganizationSecretDelete,

Schema: map[string]*schema.Schema{
"secret_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"plaintext_value": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Sensitive: true,
},
"visibility": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateValueFunc([]string{"all", "private", "selected"}),
ForceNew: true,
},
"selected_repository_ids": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
Set: schema.HashInt,
Optional: true,
},
"created_at": {
Type: schema.TypeString,
Computed: true,
},
"updated_at": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

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

secretName := d.Get("secret_name").(string)
plaintextValue := d.Get("plaintext_value").(string)

visibility := d.Get("visibility").(string)
selectedRepositories, hasSelectedRepositories := d.GetOk("selected_repository_ids")

if visibility == "selected" && !hasSelectedRepositories {
return fmt.Errorf("Cannot use visbility set to selected without selected_repository_ids")
} else if visibility != "selected" && hasSelectedRepositories {
return fmt.Errorf("Cannot use selected_repository_ids without visibility being set to selected")
}

selectedRepositoryIDs := []int64{}

if hasSelectedRepositories {
ids := selectedRepositories.(*schema.Set).List()

for _, id := range ids {
selectedRepositoryIDs = append(selectedRepositoryIDs, int64(id.(int)))
}
}

keyId, publicKey, err := getOrganizationPublicKeyDetails(owner, meta)
if err != nil {
return err
}

encryptedText, err := encryptPlaintext(plaintextValue, publicKey)
if err != nil {
return err
}

// Create an EncryptedSecret and encrypt the plaintext value into it
eSecret := &github.EncryptedSecret{
Name: secretName,
KeyID: keyId,
Visibility: visibility,
SelectedRepositoryIDs: selectedRepositoryIDs,
EncryptedValue: base64.StdEncoding.EncodeToString(encryptedText),
}

_, err = client.Actions.CreateOrUpdateOrgSecret(ctx, owner, eSecret)
if err != nil {
return err
}

d.SetId(secretName)
return resourceGithubActionsOrganizationSecretRead(d, meta)
}

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

secret, _, err := client.Actions.GetOrgSecret(ctx, owner, d.Id())
if err != nil {
if ghErr, ok := err.(*github.ErrorResponse); ok {
if ghErr.Response.StatusCode == http.StatusNotFound {
log.Printf("[WARN] Removing actions secret %s from state because it no longer exists in GitHub",
d.Id())
d.SetId("")
return nil
}
}
return err
}

d.Set("plaintext_value", d.Get("plaintext_value"))
d.Set("updated_at", secret.UpdatedAt.String())
d.Set("created_at", secret.CreatedAt.String())

return nil
}

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

log.Printf("[DEBUG] Deleting secret: %s", d.Id())
_, err := client.Actions.DeleteOrgSecret(ctx, orgName, d.Id())
return err
}

func getOrganizationPublicKeyDetails(owner string, meta interface{}) (keyId, pkValue string, err error) {
client := meta.(*Owner).v3client
ctx := context.Background()

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

return publicKey.GetKeyID(), publicKey.GetKey(), err
}
119 changes: 119 additions & 0 deletions github/resource_github_actions_organization_secret_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package github

import (
"fmt"
"strings"
"testing"

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

func TestAccGithubActionsOrganizationSecret(t *testing.T) {
t.Run("creates and updates secrets without error", func(t *testing.T) {
secretValue := "super_secret_value"
updatedSecretValue := "updated_super_secret_value"

config := fmt.Sprintf(`
resource "github_actions_organization_secret" "test_secret" {
secret_name = "test_secret_name"
plaintext_value = "%s"
visibility = "private"
}
`, secretValue)

checks := map[string]resource.TestCheckFunc{
"before": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_organization_secret.test_secret", "plaintext_value",
secretValue,
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "created_at",
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "updated_at",
),
),
"after": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_organization_secret.test_secret", "plaintext_value",
updatedSecretValue,
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "created_at",
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "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: checks["before"],
},
{
Config: strings.Replace(config,
secretValue,
updatedSecretValue, 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) {
t.Skip("individual account not supported for this operation")
})

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

t.Run("deletes secrets without error", func(t *testing.T) {
secretValue := "super_secret_value"

config := fmt.Sprintf(`
resource "github_actions_organization_secret" "test_secret" {
secret_name = "test_secret_name"
plaintext_value = "%s"
visibility = "private"
}
`, secretValue)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Destroy: 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) {
t.Skip("individual account not supported for this operation")
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})
}
4 changes: 2 additions & 2 deletions github/resource_github_actions_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ func resourceGithubActionsSecretRead(d *schema.ResourceData, meta interface{}) e
}

d.Set("plaintext_value", d.Get("plaintext_value"))
d.Set("updated_at", secret.UpdatedAt.Format("default"))
d.Set("created_at", secret.CreatedAt.Format("default"))
d.Set("updated_at", secret.UpdatedAt.String())
d.Set("created_at", secret.CreatedAt.String())

return nil
}
Expand Down
Loading

0 comments on commit 2ce7092

Please sign in to comment.