Skip to content
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

Added encrypted_value to Actions + Organizations's secrets #807

Merged
merged 4 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
123 changes: 123 additions & 0 deletions github/data_source_github_repository_branches.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package github
jcudit marked this conversation as resolved.
Show resolved Hide resolved

import (
"context"
"strings"

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

func dataSourceGithubRepositoryBranches() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubRepositoryBranchesRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"protected": {
Type: schema.TypeBool,
Required: true,
},
},
}
}

func dataSourceGithubRepositoryBranchesRead(d *schema.ResourceData, meta interface{}) error {
ctx := context.TODO()
client := meta.(*Owner).v3client

owner := meta.(*Owner).name
if explicitOwner, ok := d.GetOk("owner"); ok {
owner = explicitOwner.(string)
}

baseRepository := d.Get("base_repository").(string)
state := d.Get("state").(string)
head := d.Get("head_ref").(string)
base := d.Get("base_ref").(string)
sort := d.Get("sort_by").(string)
direction := d.Get("sort_direction").(string)

options := &github.PullRequestListOptions{
ListOptions: github.ListOptions{PerPage: 100},
State: state,
Head: head,
Base: base,
Sort: sort,
Direction: direction,
}

results := make([]map[string]interface{}, 0)

for {
pullRequests, resp, err := client.PullRequests.List(ctx, owner, baseRepository, options)
if err != nil {
return err
}

for _, pullRequest := range pullRequests {
result := map[string]interface{}{
"number": pullRequest.GetNumber(),
"body": pullRequest.GetBody(),
"draft": pullRequest.GetDraft(),
"maintainer_can_modify": pullRequest.GetMaintainerCanModify(),
"opened_at": pullRequest.GetCreatedAt().Unix(),
"state": pullRequest.GetState(),
"title": pullRequest.GetTitle(),
"updated_at": pullRequest.GetUpdatedAt().Unix(),
}

if head := pullRequest.GetHead(); head != nil {
result["head_ref"] = head.GetRef()
result["head_sha"] = head.GetSHA()

if headRepo := head.GetRepo(); headRepo != nil {
result["head_repository"] = headRepo.GetName()

if headOwner := headRepo.GetOwner(); headOwner != nil {
result["head_owner"] = headOwner.GetLogin()
}
}
}

if base := pullRequest.GetBase(); base != nil {
result["base_ref"] = base.GetRef()
result["base_sha"] = base.GetSHA()
}

labels := []string{}
for _, label := range pullRequest.Labels {
labels = append(labels, label.GetName())
}
result["labels"] = labels

if user := pullRequest.GetUser(); user != nil {
result["opened_by"] = user.GetLogin()
}

results = append(results, result)
}

if resp.NextPage == 0 {
break
}

options.Page = resp.NextPage
}

d.SetId(strings.Join([]string{
owner,
baseRepository,
state,
head,
base,
sort,
direction,
}, "/"))

d.Set("results", results)

return nil
}
33 changes: 25 additions & 8 deletions github/resource_github_actions_organization_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

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

func resourceGithubActionsOrganizationSecret() *schema.Resource {
Expand All @@ -31,11 +32,20 @@ func resourceGithubActionsOrganizationSecret() *schema.Resource {
ForceNew: true,
ValidateFunc: validateSecretNameFunc,
},
"encrypted_value": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Sensitive: true,
ConflictsWith: []string{"plaintext_value"},
ValidateFunc: validation.StringIsBase64,
},
"plaintext_value": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Sensitive: true,
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Sensitive: true,
ConflictsWith: []string{"encrypted_value"},
},
"visibility": {
Type: schema.TypeString,
Expand Down Expand Up @@ -70,6 +80,7 @@ func resourceGithubActionsOrganizationSecretCreateOrUpdate(d *schema.ResourceDat

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

visibility := d.Get("visibility").(string)
selectedRepositories, hasSelectedRepositories := d.GetOk("selected_repository_ids")
Expand All @@ -95,9 +106,14 @@ func resourceGithubActionsOrganizationSecretCreateOrUpdate(d *schema.ResourceDat
return err
}

encryptedText, err := encryptPlaintext(plaintextValue, publicKey)
if err != nil {
return err
if encryptedText, ok := d.GetOk("encrypted_value"); ok {
encryptedValue = encryptedText.(string)
} else {
encryptedBytes, err := encryptPlaintext(plaintextValue, publicKey)
if err != nil {
return err
}
encryptedValue = base64.StdEncoding.EncodeToString(encryptedBytes)
}

// Create an EncryptedSecret and encrypt the plaintext value into it
Expand All @@ -106,7 +122,7 @@ func resourceGithubActionsOrganizationSecretCreateOrUpdate(d *schema.ResourceDat
KeyID: keyId,
Visibility: visibility,
SelectedRepositoryIDs: selectedRepositoryIDs,
EncryptedValue: base64.StdEncoding.EncodeToString(encryptedText),
EncryptedValue: encryptedValue,
}

_, err = client.Actions.CreateOrUpdateOrgSecret(ctx, owner, eSecret)
Expand Down Expand Up @@ -136,6 +152,7 @@ func resourceGithubActionsOrganizationSecretRead(d *schema.ResourceData, meta in
return err
}

d.Set("encrypted_value", d.Get("encrypted_value"))
d.Set("plaintext_value", d.Get("plaintext_value"))
d.Set("created_at", secret.CreatedAt.String())
d.Set("visibility", secret.Visibility)
Expand Down
50 changes: 33 additions & 17 deletions github/resource_github_actions_organization_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,50 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
updatedSecretValue := "updated_super_secret_value"

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

resource "github_actions_organization_secret" "encrypted_secret" {
secret_name = "test_encrypted_secret"
encrypted_value = "%s"
visibility = "private"
}
`, secretValue, secretValue)

checks := map[string]resource.TestCheckFunc{
"before": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_organization_secret.test_secret", "plaintext_value",
"github_actions_organization_secret.plaintext_secret", "plaintext_value",
secretValue,
),
resource.TestCheckResourceAttr(
"github_actions_organization_secret.encrypted_secret", "encrypted_value",
secretValue,
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "created_at",
"github_actions_organization_secret.plaintext_secret", "created_at",
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "updated_at",
"github_actions_organization_secret.plaintext_secret", "updated_at",
),
),
"after": resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_organization_secret.test_secret", "plaintext_value",
"github_actions_organization_secret.plaintext_secret", "plaintext_value",
updatedSecretValue,
),
resource.TestCheckResourceAttr(
"github_actions_organization_secret.encrypted_secret", "encrypted_value",
updatedSecretValue,
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "created_at",
"github_actions_organization_secret.plaintext_secret", "created_at",
),
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret.test_secret", "updated_at",
"github_actions_organization_secret.plaintext_secret", "updated_at",
),
),
}
Expand All @@ -60,7 +74,7 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
{
Config: strings.Replace(config,
secretValue,
updatedSecretValue, 1),
updatedSecretValue, 2),
Check: checks["after"],
},
},
Expand All @@ -81,15 +95,17 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
})

t.Run("deletes secrets without error", func(t *testing.T) {
secretValue := "super_secret_value"
config := `
resource "github_actions_organization_secret" "plaintext_secret" {
secret_name = "test_plaintext_secret"
visibility = "private"
}

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

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
Expand Down Expand Up @@ -122,7 +138,7 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {

config := fmt.Sprintf(`
resource "github_actions_organization_secret" "test_secret" {
secret_name = "test_secret_name"
secret_name = "test_plaintext_secret"
plaintext_value = "%s"
visibility = "private"
}
Expand Down
30 changes: 23 additions & 7 deletions github/resource_github_actions_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@ func resourceGithubActionsSecret() *schema.Resource {
ForceNew: true,
ValidateFunc: validateSecretNameFunc,
},
"encrypted_value": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Sensitive: true,
ConflictsWith: []string{"plaintext_value"},
},
"plaintext_value": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Sensitive: true,
ConflictsWith: []string{"encrypted_value"},
},
"created_at": {
Type: schema.TypeString,
Expand All @@ -55,22 +64,28 @@ func resourceGithubActionsSecretCreateOrUpdate(d *schema.ResourceData, meta inte
repo := d.Get("repository").(string)
secretName := d.Get("secret_name").(string)
plaintextValue := d.Get("plaintext_value").(string)
var encryptedValue string

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

encryptedText, err := encryptPlaintext(plaintextValue, publicKey)
if err != nil {
return err
if encryptedText, ok := d.GetOk("encrypted_value"); ok {
encryptedValue = encryptedText.(string)
} else {
encryptedBytes, err := encryptPlaintext(plaintextValue, publicKey)
if err != nil {
return err
}
encryptedValue = base64.StdEncoding.EncodeToString(encryptedBytes)
}

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

_, err = client.Actions.CreateOrUpdateRepoSecret(ctx, owner, repo, eSecret)
Expand Down Expand Up @@ -105,6 +120,7 @@ func resourceGithubActionsSecretRead(d *schema.ResourceData, meta interface{}) e
return err
}

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

Expand Down
Loading