diff --git a/examples/app_token/main.tf b/examples/app_token/main.tf new file mode 100644 index 0000000000..4bbead22a3 --- /dev/null +++ b/examples/app_token/main.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + github = { + source = "integrations/github" + } + } +} + +provider "github" {} + +data "github_app_token" "this" { + app_id = var.app_id + installation_id = var.installation_id + pem_file = file(var.pem_file_path) +} diff --git a/examples/app_token/variables.tf b/examples/app_token/variables.tf new file mode 100644 index 0000000000..827af03b11 --- /dev/null +++ b/examples/app_token/variables.tf @@ -0,0 +1,11 @@ +variable "app_id" { + type = string +} + +variable "installation_id" { + type = string +} + +variable "pem_file_path" { + type = string +} diff --git a/github/data_source_github_app_token.go b/github/data_source_github_app_token.go new file mode 100644 index 0000000000..1dd0910c93 --- /dev/null +++ b/github/data_source_github_app_token.go @@ -0,0 +1,63 @@ +package github + +import ( + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceGithubAppToken() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGithubAppTokenRead, + + Schema: map[string]*schema.Schema{ + "app_id": { + Type: schema.TypeString, + Required: true, + Description: descriptions["app_auth.id"], + }, + "installation_id": { + Type: schema.TypeString, + Required: true, + Description: descriptions["app_auth.installation_id"], + }, + "pem_file": { + Type: schema.TypeString, + Required: true, + Description: descriptions["app_auth.pem_file"], + }, + "token": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "The generated token from the credentials.", + }, + }, + } +} + +func dataSourceGithubAppTokenRead(d *schema.ResourceData, meta interface{}) error { + appID := d.Get("app_id").(string) + installationID := d.Get("installation_id").(string) + pemFile := d.Get("pem_file").(string) + + baseURL := meta.(*Owner).v3client.BaseURL.String() + + // The Go encoding/pem package only decodes PEM formatted blocks + // that contain new lines. Some platforms, like Terraform Cloud, + // do not support new lines within Environment Variables. + // Any occurrence of \n in the `pem_file` argument's value + // (explicit value, or default value taken from + // GITHUB_APP_PEM_FILE Environment Variable) is replaced with an + // actual new line character before decoding. + pemFile = strings.Replace(pemFile, `\n`, "\n", -1) + + token, err := GenerateOAuthTokenFromApp(baseURL, appID, installationID, pemFile) + if err != nil { + return err + } + d.Set("token", token) + d.SetId("id") + + return nil +} diff --git a/github/data_source_github_app_token_test.go b/github/data_source_github_app_token_test.go new file mode 100644 index 0000000000..c2c55a1f02 --- /dev/null +++ b/github/data_source_github_app_token_test.go @@ -0,0 +1,66 @@ +package github + +import ( + "fmt" + "net/http" + "net/url" + "os" + "testing" + + "github.com/google/go-github/v53/github" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/stretchr/testify/assert" +) + +func TestAccGithubAppTokenDataSource(t *testing.T) { + expectedAccessToken := "W+2e/zjiMTweDAr2b35toCF+h29l7NW92rJIPvFrCJQK" + + owner := "test-owner" + + pemData, err := os.ReadFile(testGitHubAppPrivateKeyFile) + assert.Nil(t, err) + + t.Run("creates a application token without error", func(t *testing.T) { + ts := githubApiMock([]*mockResponse{ + { + ExpectedUri: fmt.Sprintf("/api/v3/app/installations/%s/access_tokens", testGitHubAppInstallationID), + ExpectedHeaders: map[string]string{ + "Accept": "application/vnd.github.v3+json", + }, + ResponseBody: fmt.Sprintf(`{"token": "%s"}`, expectedAccessToken), + StatusCode: 201, + }, + }) + defer ts.Close() + + httpCl := http.DefaultClient + httpCl.Transport = http.DefaultTransport + + client := github.NewClient(httpCl) + u, _ := url.Parse(ts.URL + "/") + client.BaseURL = u + + meta := &Owner{ + name: owner, + v3client: client, + } + + testSchema := map[string]*schema.Schema{ + "app_id": {Type: schema.TypeString}, + "installation_id": {Type: schema.TypeString}, + "pem_file": {Type: schema.TypeString}, + "token": {Type: schema.TypeString}, + } + + schema := schema.TestResourceDataRaw(t, testSchema, map[string]interface{}{ + "app_id": testGitHubAppID, + "installation_id": testGitHubAppInstallationID, + "pem_file": string(pemData), + "token": "", + }) + + err := dataSourceGithubAppTokenRead(schema, meta) + assert.Nil(t, err) + assert.Equal(t, expectedAccessToken, schema.Get("token")) + }) +} diff --git a/github/provider.go b/github/provider.go index a3d20d4087..32522c2e43 100644 --- a/github/provider.go +++ b/github/provider.go @@ -167,6 +167,7 @@ func Provider() terraform.ResourceProvider { "github_actions_secrets": dataSourceGithubActionsSecrets(), "github_actions_variables": dataSourceGithubActionsVariables(), "github_app": dataSourceGithubApp(), + "github_app_token": dataSourceGithubAppToken(), "github_branch": dataSourceGithubBranch(), "github_branch_protection_rules": dataSourceGithubBranchProtectionRules(), "github_collaborators": dataSourceGithubCollaborators(), diff --git a/website/docs/d/app_token.html.markdown b/website/docs/d/app_token.html.markdown new file mode 100644 index 0000000000..b224b5f609 --- /dev/null +++ b/website/docs/d/app_token.html.markdown @@ -0,0 +1,36 @@ +--- +layout: "github" +page_title: "GitHub: github_app_token" +description: |- + Generate a GitHub APP JWT. +--- + +# github\_app\_token + +Use this data source to generate a [GitHub App JWT](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app). + +## Example Usage + +```hcl +data "github_app_token" "this" { + app_id = "123456" + installation_id = "78910" + pem_file = file("foo/bar.pem") +} +``` + +## Argument Reference + +The following arguments are supported: + +* `app_id` - (Required) This is the ID of the GitHub App. + +* `installation_id` - (Required) This is the ID of the GitHub App installation. + +* `pem_file` - (Required) This is the contents of the GitHub App private key PEM file. + +## Attribute Reference + +The following additional attributes are exported: + +* `token` - The generated GitHub APP JWT. diff --git a/website/github.erb b/website/github.erb index 8b58c0f9e2..a63dad0ee5 100644 --- a/website/github.erb +++ b/website/github.erb @@ -52,6 +52,9 @@
  • github_app
  • +
  • + +
  • github_branch