Skip to content

Commit

Permalink
Merge pull request #24 from coopnorge/github_app_auth
Browse files Browse the repository at this point in the history
Support all terraform provider configuration options
  • Loading branch information
haraldsk authored Apr 21, 2023
2 parents 160002a + 87a18e5 commit 1112282
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
env:
# Common versions
GO_VERSION: '1.19'
GOLANGCI_VERSION: 'v1.50.0'
GOLANGCI_VERSION: 'v1.52.2'
DOCKER_BUILDX_VERSION: 'v0.8.2'

# Common users. We can't run a step 'if secrets.XXX != ""' but we can run a
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ NPROCS ?= 1
GO_TEST_PARALLEL := $(shell echo $$(( $(NPROCS) / 2 )))

GO_REQUIRED_VERSION ?= 1.19
GOLANGCILINT_VERSION ?= 1.50.0
GOLANGCILINT_VERSION ?= 1.52.2
GO_STATIC_PACKAGES = $(GO_PROJECT)/cmd/provider $(GO_PROJECT)/cmd/generator
GO_LDFLAGS += -X $(GO_PROJECT)/internal/version.Version=$(VERSION)
GO_SUBDIRS += cmd internal apis
Expand Down
49 changes: 41 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ You can see the API reference [here](https://doc.crds.dev/github.com/coopnorge/p

Add this to configure the provider. Reference on how to configure this
can be found at the terraform provider documentation
https://registry.terraform.io/providers/integrations/github/latest/docs
https://registry.terraform.io/providers/integrations/github/latest/docs

#### Provider config example with personal access token

```yaml
---
apiVersion: v1
kind: Secret
metadata:
Expand All @@ -41,6 +44,7 @@ metadata:
type: Opaque
stringData:
credentials: "{\"token\":\"${GH_TOKEN}\",\"owner\":\"${GH_OWNER}\"}"

---
apiVersion: github.upbound.io/v1beta1
kind: ProviderConfig
Expand All @@ -56,6 +60,35 @@ spec:

```

#### Provider config example with Github application based authentication

Note that the PEM certificate needs to be wrapped in a non-multiline string, with the characters "\n"
as newline. See Terraform provider doc for more information.
```yaml
---
apiVersion: v1
kind: Secret
metadata:
name: provider-secret
namespace: upbound-system
type: Opaque
stringData:
credentials: "{\"app_auth\": [ \"id\": \"${APP_ID}\", \"installation_id\": \"${APP_INSTALLATION_ID}\", \"pem_file\": \"${APP_PEM_FILE}\" ] ,\"owner\":\"${GH_OWNER}\"}"

---
apiVersion: github.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
name: provider-secret
namespace: upbound-system
key: credentials

```

## Supported resources

Expand All @@ -68,18 +101,18 @@ spec:
| `RepositoryFile` | `repo` | `github_repository_file` | |
| `PullRequest` | `repo` | `github_repository_pull_request` | |
| `DeployKey` | `repo` | `github_repository_deploy_key` | |
| `Team` | `team` | `github_team` | |
| `Team` | `team` | `github_team` | |
| `TeamRepository` | `team` | `github_team_repository` | |
| ActionsSecrets | actions | github_actions_secret | |
| ActionsSecrets | actions | github_actions_secret | |


## Adding resources

* Find the resource to add here: https://registry.terraform.io/providers/integrations/github/latest/docs
* 1 resource per PR prefered
* Write a test case
* Write a test case

Check this reference PR: https://github.com/coopnorge/provider-github/pull/4
Check this reference PR: https://github.com/coopnorge/provider-github/pull/4

An example diff for human generated files

Expand All @@ -93,9 +126,9 @@ index 06704c1..7adefad 100644
| `DefaultBranch` | `repo` | `github_branch_default` | name change |
| `BranchProtection` | `repo` | `github_branch_protection` | |
+| `RepositoryFile` | `repo` | `github_repository_file` | |
| `Team` | `team` | `github_team` | |
| `Team` | `team` | `github_team` | |
| `TeamRepository` | `team` | `github_team_repository` | |

diff --git a/config/external_name.go b/config/external_name.go
index 505fa1c..50440d4 100644
--- a/config/external_name.go
Expand Down Expand Up @@ -147,7 +180,7 @@ index 0000000..5684451
+ // this resource, which would be "github"
+ r.Kind = "RepositoryFile"
+ r.ShortGroup = "repo"
+
+
+ r.References["repository"] = config.Reference{
+ Type: "Repository",
+ }
Expand Down
105 changes: 84 additions & 21 deletions internal/clients/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,87 @@ import (

const (
// error messages
errNoProviderConfig = "no providerConfigRef provided"
errGetProviderConfig = "cannot get referenced ProviderConfig"
errTrackUsage = "cannot track ProviderConfig usage"
errExtractCredentials = "cannot extract credentials"
errUnmarshalCredentials = "cannot unmarshal github credentials as JSON"
errNoProviderConfig = "no providerConfigRef provided"
errGetProviderConfig = "cannot get referenced ProviderConfig"
errTrackUsage = "cannot track ProviderConfig usage"
errExtractCredentials = "cannot extract credentials"
errUnmarshalCredentials = "cannot unmarshal github credentials as JSON"
errProviderConfigurationBuilder = "cannot build configuration for terraform provider block"
errTerraformProviderMissingOwner = "github provider app_auth needs owner key to be set"

// provider config variables
keyBaseURL = "base_url"
keyOwner = "owner"
keyToken = "token"
keyBaseURL = "base_url"
keyOwner = "owner"
keyToken = "token"
keyAppAuth = "app_auth"
keyAppAuthID = "id"
keyAppAuthInstallationID = "installation_id"
keyAppAuthPemFile = "pem_file"
keyWriteDelayMs = "write_delay_ms"
keyReadDelayMs = "read_delay_ms"
)

// TerraformSetupBuilder builds Terraform a terraform.SetupFn function which
// returns Terraform provider setup configuration
type appAuth struct {
ID string `json:"id"`
InstallationID string `json:"installation_id"`
AuthPemFile string `json:"pem_file"`
}

type githubConfig struct {
BaseURL *string `json:"base_url,omitempty"`
Owner *string `json:"owner,omitempty"`
Token *string `json:"token,omitempty"`
AppAuth *[]appAuth `json:"app_auth,omitempty"`
WriteDelayMs *int `json:"write_delay_ms,omitempty"`
ReadDelayMs *int `json:"read_delay_ms,omitempty"`
}

func terraformProviderConfigurationBuilder(creds githubConfig) (terraform.ProviderConfiguration, error) {

cnf := terraform.ProviderConfiguration{}

if creds.BaseURL != nil {
cnf[keyBaseURL] = *creds.BaseURL
}

if creds.Owner != nil {
cnf[keyOwner] = *creds.Owner
}

if creds.Token != nil {
cnf[keyToken] = *creds.Token
}

if creds.AppAuth != nil {
if creds.Owner == nil {
return cnf, errors.Errorf(errTerraformProviderMissingOwner)
}

aaList := []map[string]any{}

aa := map[string]any{
keyAppAuthID: (*creds.AppAuth)[0].ID,
keyAppAuthInstallationID: (*creds.AppAuth)[0].InstallationID,
keyAppAuthPemFile: (*creds.AppAuth)[0].AuthPemFile,
}

aaList = append(aaList, aa)
cnf[keyAppAuth] = aaList
}

if creds.WriteDelayMs != nil {
cnf[keyWriteDelayMs] = *creds.WriteDelayMs
}

if creds.ReadDelayMs != nil {
cnf[keyReadDelayMs] = *creds.ReadDelayMs
}

return cnf, nil

}

// TerraformSetupBuilder builds Terraform a terraform.SetupFn function which returns Terraform provider setup configuration
func TerraformSetupBuilder(version, providerSource, providerVersion string) terraform.SetupFn {
return func(ctx context.Context, client client.Client, mg resource.Managed) (terraform.Setup, error) {
ps := terraform.Setup{
Expand All @@ -48,6 +115,7 @@ func TerraformSetupBuilder(version, providerSource, providerVersion string) terr
if configRef == nil {
return ps, errors.New(errNoProviderConfig)
}

pc := &v1beta1.ProviderConfig{}
if err := client.Get(ctx, types.NamespacedName{Name: configRef.Name}, pc); err != nil {
return ps, errors.Wrap(err, errGetProviderConfig)
Expand All @@ -62,22 +130,17 @@ func TerraformSetupBuilder(version, providerSource, providerVersion string) terr
if err != nil {
return ps, errors.Wrap(err, errExtractCredentials)
}
creds := map[string]string{}

creds := githubConfig{}
if err := json.Unmarshal(data, &creds); err != nil {
return ps, errors.Wrap(err, errUnmarshalCredentials)
}

// set provider configuration
ps.Configuration = map[string]any{}
if v, ok := creds[keyBaseURL]; ok {
ps.Configuration[keyBaseURL] = v
}
if v, ok := creds[keyOwner]; ok {
ps.Configuration[keyOwner] = v
}
if v, ok := creds[keyToken]; ok {
ps.Configuration[keyToken] = v
ps.Configuration, err = terraformProviderConfigurationBuilder(creds)
if err != nil {
return ps, errors.Wrap(err, errProviderConfigurationBuilder)
}

return ps, nil

}
Expand Down

0 comments on commit 1112282

Please sign in to comment.