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

[#803] Allow GitHub App PEM data to be passed directly #804

Merged
merged 1 commit into from
Jun 8, 2021
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Unreleased

BREAKING CHANGES:

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

## 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
3 changes: 2 additions & 1 deletion github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package github

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
)
Expand Down Expand Up @@ -150,7 +151,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
4 changes: 3 additions & 1 deletion website/docs/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ The following arguments are supported in the `provider` block:
* `app_auth` - (Optional) Configuration block to use GitHub App installation token. When not provided, the provider can only access resources available anonymously.
* `id` - (Required) This is the ID of the GitHub App. It can sourced from the `GITHUB_APP_ID` environment variable.
* `installation_id` - (Required) This is the ID of the GitHub App installation. It can sourced from the `GITHUB_APP_INSTALLATION_ID` environment variable.
* `pem_file` - (Required) This is the path to the GitHub App private key file. It can sourced from the `GITHUB_APP_PEM_FILE` environment variable.
* `pem_file` - (Required) This is the contents of the GitHub App private key PEM file. It can also be sourced from the `GITHUB_APP_PEM_FILE` environment variable.

Note: If you have a PEM file on disk, you can pass it in via `pem_file = file("path/to/file.pem")`.

For backwards compatibility, if more than one of `owner`, `organization`,
`GITHUB_OWNER` and `GITHUB_ORGANIZATION` are set, the first in this
Expand Down