-
Notifications
You must be signed in to change notification settings - Fork 777
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added resources for Environment + Environment Secrets (#805)
* Added resources for Environment + Environment Secrets * Added support for encrypted value * Added conflicts with, fixed formatting and changes to go-github * Fixed indentation * Fixed indentation * Fixed indentation * Encrypted value needs to be in Base64 format * fixup! add new resources to website.erb Co-authored-by: Jeremy Udit <[email protected]>
- v6.5.0
- v6.4.0
- v6.3.1
- v6.3.0
- v6.2.3
- v6.2.2
- v6.2.1
- v6.2.0
- v6.1.0
- v6.0.1
- v6.0.0
- v6.0.0-rc2
- v6.0.0-rc1
- v6.0.0-beta
- v6.0.0-alpha
- v5.45.0
- v5.44.0
- v5.43.0
- v5.42.0
- v5.41.0
- v5.40.0
- v5.39.0
- v5.38.0
- v5.37.0
- v5.36.0
- v5.35.0
- v5.34.0
- v5.33.0
- v5.32.0
- v5.31.0
- v5.30.1
- v5.30.0
- v5.29.0
- v5.28.1
- v5.28.0
- v5.27.0
- v5.26.0
- v5.25.1
- v5.25.0
- v5.24.0
- v5.23.0
- v5.22.0
- v5.21.1
- v5.20.0
- v5.19.0
- v5.18.3
- v5.18.2
- v5.18.0
- v5.17.0
- v5.16.0
- v5.15.0
- v5.14.0
- v5.13.0
- v5.12.0
- v5.11.0
- v5.10.0
- v5.9.2
- v5.9.1
- v5.9.0
- v5.8.0
- v5.7.0
- v5.6.0
- v5.5.0
- v5.4.0
- v5.3.0
- v5.2.0
- v5.1.0
- v5.0.0
- v4.31.0
- v4.30.0
- v4.29.0
- v4.28.0
- v4.26.1
- v4.26.0
- v4.25.0
- v4.25.0-alpha
- v4.24.1
- v4.24.0
- v4.23.0
- v4.22.0
- v4.21.0
- v4.20.1
- v4.20.0
- v4.19.2
- v4.19.1
- v4.19.0
- v4.18.2
- v4.18.1
- v4.18.0
- v4.17.0
- v4.16.0
- v4.15.1
- v4.15.0
- v4.14.0
- v4.13.0
- v4.12.2
- v4.12.1
- v4.12.0
Showing
9 changed files
with
852 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"encoding/base64" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/google/go-github/v35/github" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/validation" | ||
) | ||
|
||
func resourceGithubActionsEnvironmentSecret() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceGithubActionsEnvironmentSecretCreateOrUpdate, | ||
Read: resourceGithubActionsEnvironmentSecretRead, | ||
Delete: resourceGithubActionsEnvironmentSecretDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"repository": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"environment": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"secret_name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateSecretNameFunc, | ||
}, | ||
"encrypted_value": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
Sensitive: true, | ||
ConflictsWith: []string{"plaintext_value"}, | ||
ValidateFunc: validation.StringIsBase64, | ||
}, | ||
"plaintext_value": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
Sensitive: true, | ||
ConflictsWith: []string{"encrypted_value"}, | ||
}, | ||
"created_at": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"updated_at": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceGithubActionsEnvironmentSecretCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
owner := meta.(*Owner).name | ||
ctx := context.Background() | ||
|
||
repoName := d.Get("repository").(string) | ||
envName := d.Get("environment").(string) | ||
secretName := d.Get("secret_name").(string) | ||
plaintextValue := d.Get("plaintext_value").(string) | ||
var encryptedValue string | ||
|
||
repo, _, err := client.Repositories.Get(ctx, owner, repoName) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
keyId, publicKey, err := getEnvironmentPublicKeyDetails(repo.GetID(), envName, meta) | ||
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: encryptedValue, | ||
} | ||
|
||
_, err = client.Actions.CreateOrUpdateEnvSecret(ctx, repo.GetID(), envName, eSecret) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(buildThreePartID(repoName, envName, secretName)) | ||
return resourceGithubActionsEnvironmentSecretRead(d, meta) | ||
} | ||
|
||
func resourceGithubActionsEnvironmentSecretRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
owner := meta.(*Owner).name | ||
ctx := context.Background() | ||
|
||
repoName, envName, secretName, err := parseThreePartID(d.Id(), "repository", "environment", "secret_name") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
repo, _, err := client.Repositories.Get(ctx, owner, repoName) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
secret, _, err := client.Actions.GetEnvSecret(ctx, repo.GetID(), envName, secretName) | ||
if err != nil { | ||
if ghErr, ok := err.(*github.ErrorResponse); ok { | ||
if ghErr.Response.StatusCode == http.StatusNotFound { | ||
log.Printf("[WARN] Removing environment secret %s from state because it no longer exists in GitHub", | ||
d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
} | ||
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()) | ||
|
||
// This is a drift detection mechanism based on timestamps. | ||
// | ||
// If we do not currently store the "updated_at" field, it means we've only | ||
// just created the resource and the value is most likely what we want it to | ||
// be. | ||
// | ||
// If the resource is changed externally in the meantime then reading back | ||
// the last update timestamp will return a result different than the | ||
// timestamp we've persisted in the state. In that case, we can no longer | ||
// trust that the value (which we don't see) is equal to what we've declared | ||
// previously. | ||
// | ||
// The only solution to enforce consistency between is to mark the resource | ||
// as deleted (unset the ID) in order to fix potential drift by recreating | ||
// the resource. | ||
if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { | ||
log.Printf("[WARN] The environment secret %s has been externally updated in GitHub", d.Id()) | ||
d.SetId("") | ||
} else if !ok { | ||
d.Set("updated_at", secret.UpdatedAt.String()) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceGithubActionsEnvironmentSecretDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
owner := meta.(*Owner).name | ||
ctx := context.WithValue(context.Background(), ctxId, d.Id()) | ||
|
||
repoName, envName, secretName, err := parseThreePartID(d.Id(), "repository", "environment", "secret_name") | ||
if err != nil { | ||
return err | ||
} | ||
repo, _, err := client.Repositories.Get(ctx, owner, repoName) | ||
if err != nil { | ||
return err | ||
} | ||
log.Printf("[DEBUG] Deleting environment secret: %s", d.Id()) | ||
_, err = client.Actions.DeleteEnvSecret(ctx, repo.GetID(), envName, secretName) | ||
|
||
return err | ||
} | ||
|
||
func getEnvironmentPublicKeyDetails(repoID int64, envName string, meta interface{}) (keyId, pkValue string, err error) { | ||
client := meta.(*Owner).v3client | ||
ctx := context.Background() | ||
|
||
publicKey, _, err := client.Actions.GetEnvPublicKey(ctx, int(repoID), envName) | ||
if err != nil { | ||
return keyId, pkValue, err | ||
} | ||
|
||
return publicKey.GetKeyID(), publicKey.GetKey(), err | ||
} |
171 changes: 171 additions & 0 deletions
171
github/resource_github_actions_environment_secret_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package github | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource" | ||
) | ||
|
||
func TestAccGithubActionsEnvironmentSecret(t *testing.T) { | ||
|
||
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) | ||
|
||
t.Run("creates and updates secrets without error", func(t *testing.T) { | ||
|
||
secretValue := "super_secret_value" | ||
updatedSecretValue := "updated_super_secret_value" | ||
|
||
config := fmt.Sprintf(` | ||
resource "github_repository" "test" { | ||
name = "tf-acc-test-%s" | ||
} | ||
resource "github_repository_environment" "test" { | ||
repository = github_repository.test.name | ||
environment = "test_environment_name" | ||
} | ||
resource "github_actions_environment_secret" "plaintext_secret" { | ||
repository = github_repository.test.name | ||
environment = github_repository_environment.test.environment | ||
secret_name = "test_plaintext_secret_name" | ||
plaintext_value = "%s" | ||
} | ||
resource "github_actions_environment_secret" "encrypted_secret" { | ||
repository = github_repository.test.name | ||
environment = github_repository_environment.test.environment | ||
secret_name = "test_encrypted_secret_name" | ||
encrypted_value = "%s" | ||
} | ||
`, randomID, secretValue, secretValue) | ||
|
||
checks := map[string]resource.TestCheckFunc{ | ||
"before": resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr( | ||
"github_actions_environment_secret.plaintext_secret", "plaintext_value", | ||
secretValue, | ||
), | ||
resource.TestCheckResourceAttr( | ||
"github_actions_environment_secret.encrypted_secret", "encrypted_value", | ||
secretValue, | ||
), | ||
resource.TestCheckResourceAttrSet( | ||
"github_actions_environment_secret.plaintext_secret", "created_at", | ||
), | ||
resource.TestCheckResourceAttrSet( | ||
"github_actions_environment_secret.plaintext_secret", "updated_at", | ||
), | ||
), | ||
"after": resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr( | ||
"github_actions_environment_secret.plaintext_secret", "plaintext_value", | ||
updatedSecretValue, | ||
), | ||
resource.TestCheckResourceAttr( | ||
"github_actions_environment_secret.encrypted_secret", "encrypted_value", | ||
updatedSecretValue, | ||
), | ||
resource.TestCheckResourceAttrSet( | ||
"github_actions_environment_secret.plaintext_secret", "created_at", | ||
), | ||
resource.TestCheckResourceAttrSet( | ||
"github_actions_environment_secret.plaintext_secret", "updated_at", | ||
), | ||
), | ||
} | ||
|
||
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: checks["before"], | ||
}, | ||
{ | ||
Config: strings.Replace(config, | ||
secretValue, | ||
updatedSecretValue, 2), | ||
Check: checks["after"], | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
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) | ||
}) | ||
|
||
}) | ||
|
||
t.Run("deletes secrets without error", func(t *testing.T) { | ||
|
||
secretValue := "super_secret_value" | ||
|
||
config := fmt.Sprintf(` | ||
resource "github_repository" "test" { | ||
name = "tf-acc-test-%s" | ||
} | ||
resource "github_repository_environment" "test" { | ||
repository = github_repository.test.name | ||
environment = "test_environment_name" | ||
} | ||
resource "github_actions_environment_secret" "plaintext_secret" { | ||
repository = github_repository.test.name | ||
environment = github_repository_environment.test.environment | ||
secret_name = "test_plaintext_secret_name" | ||
plaintext_value = "%s" | ||
} | ||
resource "github_actions_environment_secret" "encrypted_secret" { | ||
repository = github_repository.test.name | ||
environment = github_repository_environment.test.environment | ||
secret_name = "test_encrypted_secret_name" | ||
encrypted_value = "%s" | ||
} | ||
`, randomID, secretValue, secretValue) | ||
|
||
testCase := func(t *testing.T, mode string) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { skipUnlessMode(t, mode) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: config, | ||
Destroy: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
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) | ||
}) | ||
|
||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"net/http" | ||
"strconv" | ||
|
||
"github.com/google/go-github/v35/github" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/validation" | ||
) | ||
|
||
func resourceGithubRepositoryEnvironment() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceGithubRepositoryEnvironmentCreate, | ||
Read: resourceGithubRepositoryEnvironmentRead, | ||
Update: resourceGithubRepositoryEnvironmentUpdate, | ||
Delete: resourceGithubRepositoryEnvironmentDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
Schema: map[string]*schema.Schema{ | ||
"repository": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"environment": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"wait_timer": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
ValidateFunc: validation.IntBetween(0, 43200), | ||
}, | ||
"reviewers": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
MaxItems: 6, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"teams": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Schema{Type: schema.TypeInt}, | ||
}, | ||
"users": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Schema{Type: schema.TypeInt}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"deployment_branch_policy": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
MaxItems: 1, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"protected_branches": { | ||
Type: schema.TypeBool, | ||
Required: true, | ||
}, | ||
"custom_branch_policies": { | ||
Type: schema.TypeBool, | ||
Required: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
|
||
owner := meta.(*Owner).name | ||
repoName := d.Get("repository").(string) | ||
envName := d.Get("environment").(string) | ||
updateData := createUpdateEnvironmentData(d, meta) | ||
|
||
ctx := context.Background() | ||
|
||
log.Printf("[DEBUG] Creating repository environment: %s/%s/%s", owner, repoName, envName) | ||
_, _, err := client.Repositories.CreateUpdateEnvironment(ctx, owner, repoName, envName, &updateData) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(buildTwoPartID(repoName, envName)) | ||
|
||
return resourceGithubRepositoryEnvironmentRead(d, meta) | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
|
||
owner := meta.(*Owner).name | ||
repoName, envName, err := parseTwoPartID(d.Id(), "repository", "environment") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
ctx := context.WithValue(context.Background(), ctxId, d.Id()) | ||
|
||
log.Printf("[DEBUG] Reading repository environment: %s (%s/%s/%s)", d.Id(), owner, repoName, envName) | ||
env, _, err := client.Repositories.GetEnvironment(ctx, owner, repoName, envName) | ||
if err != nil { | ||
if ghErr, ok := err.(*github.ErrorResponse); ok { | ||
if ghErr.Response.StatusCode == http.StatusNotFound { | ||
log.Printf("[WARN] Removing repository environment %s from state because it no longer exists in GitHub", | ||
d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
d.Set("repository", repoName) | ||
d.Set("environment", envName) | ||
|
||
for _, pr := range env.ProtectionRules { | ||
switch *pr.Type { | ||
case "wait_timer": | ||
d.Set("wait_timer", pr.WaitTimer) | ||
|
||
case "required_reviewers": | ||
teams := make([]int64, 0) | ||
users := make([]int64, 0) | ||
|
||
for _, r := range pr.Reviewers { | ||
switch *r.Type { | ||
case "Team": | ||
teams = append(teams, *r.Reviewer.(*github.Team).ID) | ||
case "User": | ||
users = append(users, *r.Reviewer.(*github.User).ID) | ||
} | ||
} | ||
d.Set("reviewers", []interface{}{ | ||
map[string]interface{}{ | ||
"teams": teams, | ||
"users": users, | ||
}, | ||
}) | ||
} | ||
} | ||
|
||
if env.DeploymentBranchPolicy != nil { | ||
d.Set("deployment_branch_policy", []interface{}{ | ||
map[string]interface{}{ | ||
"protected_branches": env.DeploymentBranchPolicy.ProtectedBranches, | ||
"custom_branch_policies": env.DeploymentBranchPolicy.CustomBranchPolicies, | ||
}, | ||
}) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
|
||
owner := meta.(*Owner).name | ||
repoName := d.Get("repository").(string) | ||
envName := d.Get("environment").(string) | ||
updateData := createUpdateEnvironmentData(d, meta) | ||
|
||
ctx := context.Background() | ||
|
||
log.Printf("[DEBUG] Updating repository environment: %s/%s/%s", owner, repoName, envName) | ||
resultKey, _, err := client.Repositories.CreateUpdateEnvironment(ctx, owner, repoName, envName, &updateData) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(buildTwoPartID(repoName, strconv.FormatInt(resultKey.GetID(), 10))) | ||
|
||
return resourceGithubRepositoryEnvironmentRead(d, meta) | ||
} | ||
|
||
func resourceGithubRepositoryEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*Owner).v3client | ||
|
||
owner := meta.(*Owner).name | ||
repoName, envName, err := parseTwoPartID(d.Id(), "repository", "environment") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
ctx := context.WithValue(context.Background(), ctxId, d.Id()) | ||
|
||
log.Printf("[DEBUG] Deleting repository environment: %s/%s/%s", owner, repoName, envName) | ||
_, err = client.Repositories.DeleteEnvironment(ctx, owner, repoName, envName) | ||
return err | ||
} | ||
|
||
func createUpdateEnvironmentData(d *schema.ResourceData, meta interface{}) github.CreateUpdateEnvironment { | ||
data := github.CreateUpdateEnvironment{} | ||
|
||
if v, ok := d.GetOk("wait_timer"); ok { | ||
data.WaitTimer = github.Int(v.(int)) | ||
} | ||
|
||
if v, ok := d.GetOk("reviewers"); ok { | ||
envReviewers := make([]*github.EnvReviewers, 0) | ||
|
||
for _, team := range expandReviewers(v, "teams") { | ||
envReviewers = append(envReviewers, &github.EnvReviewers{ | ||
Type: github.String("Team"), | ||
ID: github.Int64(team), | ||
}) | ||
} | ||
|
||
for _, user := range expandReviewers(v, "users") { | ||
envReviewers = append(envReviewers, &github.EnvReviewers{ | ||
Type: github.String("User"), | ||
ID: github.Int64(user), | ||
}) | ||
} | ||
|
||
data.Reviewers = envReviewers | ||
} | ||
|
||
if v, ok := d.GetOk("deployment_branch_policy"); ok { | ||
policy := v.([]interface{})[0].(map[string]interface{}) | ||
data.DeploymentBranchPolicy = &github.BranchPolicy{ | ||
ProtectedBranches: github.Bool(policy["protected_branches"].(bool)), | ||
CustomBranchPolicies: github.Bool(policy["custom_branch_policies"].(bool)), | ||
} | ||
} | ||
|
||
return data | ||
} | ||
|
||
func expandReviewers(v interface{}, target string) []int64 { | ||
res := make([]int64, 0) | ||
m := v.([]interface{})[0] | ||
if m != nil { | ||
if v, ok := m.(map[string]interface{})[target]; ok { | ||
vL := v.(*schema.Set).List() | ||
for _, v := range vL { | ||
res = append(res, int64(v.(int))) | ||
} | ||
} | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package github | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource" | ||
) | ||
|
||
func TestAccGithubRepositoryEnvironment(t *testing.T) { | ||
|
||
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) | ||
|
||
t.Run("creates a repository environment", func(t *testing.T) { | ||
|
||
config := fmt.Sprintf(` | ||
data "github_user" "current" { | ||
username = "" | ||
} | ||
resource "github_repository" "test" { | ||
name = "tf-acc-test-%s" | ||
} | ||
resource "github_repository_environment" "test" { | ||
repository = github_repository.test.name | ||
environment = "test_environment_name" | ||
wait_timer = 10000 | ||
reviewers { | ||
users = [data.github_user.current.id] | ||
} | ||
deployment_branch_policy { | ||
protected_branches = true | ||
custom_branch_policies = false | ||
} | ||
} | ||
`, randomID) | ||
|
||
check := resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr( | ||
"github_repository_environment.test", "environment", | ||
"test_environment_name", | ||
), | ||
) | ||
|
||
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) | ||
}) | ||
|
||
}) | ||
} |
8 changes: 4 additions & 4 deletions
8
vendor/github.com/google/go-github/v35/github/actions_secrets.go
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
--- | ||
layout: "github" | ||
page_title: "GitHub: github_actions_environment_secret" | ||
description: |- | ||
Creates and manages an Action Secret within a GitHub repository environment | ||
--- | ||
|
||
# github_actions_environment_secret | ||
|
||
This resource allows you to create and manage GitHub Actions secrets within your GitHub repository environments. | ||
You must have write access to a repository to use this resource. | ||
|
||
Secret values are encrypted using the [Go '/crypto/box' module](https://godoc.org/golang.org/x/crypto/nacl/box) which is | ||
interoperable with [libsodium](https://libsodium.gitbook.io/doc/). Libsodium is used by GitHub to decrypt secret values. | ||
|
||
For the purposes of security, the contents of the `plaintext_value` field have been marked as `sensitive` to Terraform, | ||
but it is important to note that **this does not hide it from state files**. You should treat state as sensitive always. | ||
It is also advised that you do not store plaintext values in your code but rather populate the `encrypted_value` | ||
using fields from a resource, data source or variable as, while encrypted in state, these will be easily accessible | ||
in your code. See below for an example of this abstraction. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "github_actions_environment_secret" "example_secret" { | ||
environment = "example_environment" | ||
secret_name = "example_secret_name" | ||
plaintext_value = var.some_secret_string | ||
} | ||
resource "github_actions_environment_secret" "example_secret" { | ||
environment = "example_environment" | ||
secret_name = "example_secret_name" | ||
encrypted_value = var.some_encrypted_secret_string | ||
} | ||
``` | ||
|
||
```hcl | ||
data "github_repository" "repo" { | ||
full_name = "my-org/repo" | ||
} | ||
resource "github_repository_environment" "repo_environment" { | ||
repository = data.github_repository.repo | ||
environment = "example_environment" | ||
} | ||
resource "github_actions_environment_secret" "test_secret" { | ||
repository = data.github_repository.repo | ||
environment = github_repository_environment.repo_environment.environment | ||
secret_name = "test_secret_name" | ||
plaintext_value = "%s" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
|
||
* `repository` - (Required) Name of the repository. | ||
* `environment` - (Required) Name of the environment. | ||
* `secret_name` - (Required) Name of the secret. | ||
* `encrypted_value` - (Optional) Encrypted value of the secret using the Github public key in Base64 format. | ||
* `plaintext_value` - (Optional) Plaintext value of the secret to be encrypted. | ||
|
||
## Attributes Reference | ||
|
||
* `created_at` - Date of actions_environment_secret creation. | ||
* `updated_at` - Date of actions_environment_secret update. | ||
|
||
## Import | ||
|
||
This resource can be imported using an ID made up of the secret name: | ||
|
||
``` | ||
$ terraform import github_actions_environment_secret.test_secret test_secret_name | ||
``` | ||
|
||
NOTE: the implementation is limited in that it won't fetch the value of the | ||
`plaintext_value` field when importing. You may need to ignore changes for the | ||
`plaintext_value` as a workaround. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- | ||
layout: "github" | ||
page_title: "GitHub: github_repository_environment" | ||
description: |- | ||
Creates and manages environments for GitHub repositories | ||
--- | ||
|
||
# github_repository_environment | ||
|
||
This resource allows you to create and manage environments for a GitHub repository. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
data "github_user" "current" { | ||
username = "" | ||
} | ||
resource "github_repository" "example" { | ||
name = "example" | ||
description = "My awesome codebase" | ||
} | ||
resource "github_repository_environment" "example" { | ||
name = "A Repository Project" | ||
repository = github_repository.example.name | ||
reviewers { | ||
users = [data.github_user.current.id] | ||
} | ||
deployment_branch_policy { | ||
protected_branches = true | ||
custom_branch_policies = false | ||
} | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `name` - (Required) The name of the environment. | ||
|
||
* `repository` - (Required) The repository of the environment. | ||
|
||
* `wait_timer` - (Optional) Amount of time to delay a job after the job is initially triggered. | ||
|
||
### Reviewers | ||
|
||
The `reviewers` block supports the following: | ||
|
||
* `teams` - (Optional) Up to 6 IDs for teams who may review jobs that reference the environment. Reviewers must have at least read access to the repository. Only one of the required reviewers needs to approve the job for it to proceed. | ||
|
||
* `users` - (Optional) Up to 6 IDs for users who may review jobs that reference the environment. Reviewers must have at least read access to the repository. Only one of the required reviewers needs to approve the job for it to proceed. | ||
|
||
#### Deployment Branch Policy #### | ||
|
||
The `deployment_branch_policy` block supports the following: | ||
|
||
* `protected_branches` - (Required) Whether only branches with branch protection rules can deploy to this environment. | ||
|
||
* `custom_branch_policies` - (Required) Whether only branches that match the specified name patterns can deploy to this environment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters