Skip to content

Commit

Permalink
Merge branch 'integrations:master' into environment
Browse files Browse the repository at this point in the history
  • Loading branch information
nadenf committed Jun 12, 2021
2 parents 8997ff5 + b9b5aa1 commit f4dc1c4
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 88 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## 4.11.0 (Jun 7, 2021)

BREAKING CHANGES:

- Allow PEM data to be passed directly for GitHub App provider authentication ([#803](https://github.com/integrations/terraform-provider-github/issues/803))

ENHANCEMENTS:

- Add `encrypted_value` field to `github_actions_secret` and `github_actions_organization_secret` resources ([#807](https://github.com/integrations/terraform-provider-github/issues/807))

BUG FIXES:

- Fix error handling when branch does not exist for `github_branch` resource ([#806](https://github.com/integrations/terraform-provider-github/issues/806))

## 4.10.1 (May 25, 2021)

BUG FIXES:
Expand Down
23 changes: 12 additions & 11 deletions github/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@ import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
"io/ioutil"
"net/http"
"time"
)

// GenerateOAuthTokenFromApp generates a GitHub OAuth access token from a set of valid GitHub App credentials. The
// returned token can be used to interact with both GitHub's REST and GraphQL APIs.
func GenerateOAuthTokenFromApp(baseURL, appID, appInstallationID, appPemFile string) (string, error) {
pemData, err := ioutil.ReadFile(appPemFile)
if err != nil {
return "", err
}
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)

appJWT, err := generateAppJWT(appID, time.Now(), pemData)
// GenerateOAuthTokenFromApp generates a GitHub OAuth access token from a set of valid GitHub App credentials.
// The returned token can be used to interact with both GitHub's REST and GraphQL APIs.
func GenerateOAuthTokenFromApp(baseURL, appID, appInstallationID, pemData string) (string, error) {
appJWT, err := generateAppJWT(appID, time.Now(), []byte(pemData))
if err != nil {
return "", err
}
Expand Down Expand Up @@ -73,6 +70,10 @@ func getInstallationAccessToken(baseURL string, jwt string, installationID strin

func generateAppJWT(appID string, now time.Time, pemData []byte) (string, error) {
block, _ := pem.Decode(pemData)
if block == nil {
return "", errors.New("No decodeable PEM data found")
}

privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
Expand Down
17 changes: 7 additions & 10 deletions github/apps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,30 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
"io/ioutil"
"strings"
"testing"
"time"

"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)

const (
testGitHubAppID string = "123456789"
testGitHubAppInstallationID string = "987654321"
testGitHubAppPrivateKeyFile string = "test-fixtures/github-app-key.pem"
testGitHubAppPublicKeyFile string = "test-fixtures/github-app-key.pub"
testGitHubAppPrivateKeyFile string = "test-fixtures/github-app-key.pem"
)

var (
testEpochTime = time.Unix(0, 0)

testGitHubAppPrivateKeyPemData, _ = ioutil.ReadFile(testGitHubAppPrivateKeyFile)
)

func TestGenerateAppJWT(t *testing.T) {
pemData, err := ioutil.ReadFile(testGitHubAppPrivateKeyFile)
if err != nil {
t.Logf("Failed to read private key file '%s': %s", testGitHubAppPrivateKeyFile, err)
t.FailNow()
}

appJWT, err := generateAppJWT(testGitHubAppID, testEpochTime, pemData)
appJWT, err := generateAppJWT(testGitHubAppID, testEpochTime, testGitHubAppPrivateKeyPemData)
t.Log(appJWT)
if err != nil {
t.Logf("Failed to generate GitHub app JWT: %s", err)
Expand Down
19 changes: 12 additions & 7 deletions github/data_source_github_branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package github

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

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

Expand Down Expand Up @@ -46,13 +47,17 @@ func dataSourceGithubBranchRead(d *schema.ResourceData, meta interface{}) error
branchName := d.Get("branch").(string)
branchRefName := "refs/heads/" + branchName

log.Printf("[DEBUG] Reading GitHub branch reference %s/%s (%s)",
orgName, repoName, branchRefName)
ref, resp, err := client.Git.GetRef(
context.TODO(), orgName, repoName, branchRefName)
log.Printf("[DEBUG] Reading GitHub branch reference %s/%s (%s)", orgName, repoName, branchRefName)
ref, resp, err := client.Git.GetRef(context.TODO(), orgName, repoName, branchRefName)
if err != nil {
return fmt.Errorf("Error reading GitHub branch reference %s/%s (%s): %s",
orgName, repoName, branchRefName, err)
if err, ok := err.(*github.ErrorResponse); ok {
if err.Response.StatusCode == http.StatusNotFound {
log.Printf("Error reading GitHub branch reference %s/%s (%s): %s", orgName, repoName, branchRefName, err)
d.SetId("")
return nil
}
}
return err
}

d.SetId(buildTwoPartID(repoName, branchName))
Expand Down
47 changes: 47 additions & 0 deletions github/data_source_github_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,51 @@ func TestAccGithubBranchDataSource(t *testing.T) {
})

})

t.Run("queries an invalid branch without error", func(t *testing.T) {

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

check := resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(
"data.github_branch.test", "id",
),
)

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

})
}
2 changes: 1 addition & 1 deletion github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func init() {
"`token`. Anonymous mode is enabled if both `token` and `app_auth` are not set.",
"app_auth.id": "The GitHub App ID.",
"app_auth.installation_id": "The GitHub App installation instance ID.",
"app_auth.pem_file": "The GitHub App PEM file path.",
"app_auth.pem_file": "The GitHub App PEM file contents.",
}
}

Expand Down
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
Loading

0 comments on commit f4dc1c4

Please sign in to comment.