Skip to content

Commit

Permalink
test: added function with secret tests, added helpers for secret crea…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
andrew-s committed Aug 8, 2024
1 parent 43004de commit bb9518c
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 84 deletions.
75 changes: 70 additions & 5 deletions tests/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package tests

import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"math/rand"
math_rand "math/rand"
"os"
"path/filepath"
"strings"

"github.com/google/uuid"
openapi_chaos_client "github.com/qernal/openapi-chaos-go-client"
"golang.org/x/crypto/nacl/box"
"golang.org/x/oauth2/clientcredentials"
)

Expand Down Expand Up @@ -135,7 +138,6 @@ func getDefaultHost(projid string) (string, error) {
}

func cleanupTerraformFiles(modulePath string) error {

// List of files/directories to remove
tfFiles := []string{
".terraform",
Expand All @@ -155,11 +157,74 @@ func cleanupTerraformFiles(modulePath string) error {
return nil
}

func fetchDek(projectID string) (string, int32, error) {
client := qernalClient()
resp, r, err := client.SecretsAPI.ProjectsSecretsGet(context.Background(), projectID, "dek").Execute()

if err != nil {
fmt.Fprintf(os.Stderr, "Error when calling `ProjectsAPI.ProjectsSecretsGet``: %v\n", err)
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)

return "", 0, err
}

return resp.Payload.SecretMetaResponseDek.Public, resp.Revision, nil
}

func encryptLocalSecret(pk, secret string) (string, error) {
pubKey, err := base64.StdEncoding.DecodeString(pk)
if err != nil {
return "", err
}

var pubKeyBytes [32]byte
copy(pubKeyBytes[:], pubKey)

secretBytes := []byte(secret)

var out []byte
encrypted, err := box.SealAnonymous(out, secretBytes, &pubKeyBytes, rand.Reader)
if err != nil {
return "", err
}

return base64.StdEncoding.EncodeToString(encrypted), nil
}

func createSecretEnv(projid string, secretname string) (string, string, error) {
dek, dekRevision, err := fetchDek(projid)
if err != nil {
return "", "", err
}

encryptedSecret, err := encryptLocalSecret(dek, secretname)
if err != nil {
return "", "", err
}

client := qernalClient()
secretEnvBody := *openapi_chaos_client.NewSecretBody(secretname, openapi_chaos_client.SECRETCREATETYPE_ENVIRONMENT, openapi_chaos_client.SecretCreatePayload{
SecretEnvironment: &openapi_chaos_client.SecretEnvironment{
EnvironmentValue: encryptedSecret,
},
}, fmt.Sprintf("keys/dek/%d", dekRevision))
resp, r, err := client.SecretsAPI.ProjectsSecretsCreate(context.Background(), projid).SecretBody(secretEnvBody).Execute()

if err != nil {
fmt.Fprintf(os.Stderr, "Error when calling `ProjectsAPI.ProjectsSecretsCreate``: %v\n", err)
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)

return "", "", err
}

return resp.Name, fmt.Sprintf("projects:%s/%s@%d", projid, resp.Name, resp.Revision), nil
}

func randomSecretName() string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, 4)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
b[i] = charset[math_rand.Intn(len(charset))]
}
return fmt.Sprintf("terra%s", string(b))
return fmt.Sprintf("TERRA_%s", string(b))
}
234 changes: 158 additions & 76 deletions tests/qernal_function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ package tests
import (
"fmt"
"os"
"strings"
"testing"
"time"

"github.com/google/uuid"
"github.com/gruntwork-io/terratest/modules/files"
http_helper "github.com/gruntwork-io/terratest/modules/http-helper"
"github.com/gruntwork-io/terratest/modules/terraform"
)

// func validateResponseBody(status int, body string) bool {
// if status == 200 && strings.Contains(body, "Hello Word") {
// return true
// }
func validateResponseBody(status int, body string) bool {
if status == 200 && strings.Contains(body, "Hello Word") {
return true
}

// return false
// }
return false
}

func TestValidFunction(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -68,13 +71,13 @@ func TestValidFunction(t *testing.T) {
// tfFunctionName := terraform.Output(t, terraformOptions, "function_name")
// assert.Equal(t, functionName, tfFunctionName)

// // validate our function deployed
// host, err := getDefaultHost(projId)
// if err != nil {
// t.Fatal(err)
// }
// validate our function deployed
host, err := getDefaultHost(projId)
if err != nil {
t.Fatal(err)
}

// http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 30, 3*time.Second, validateResponseBody)
http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 10, 3*time.Second, validateResponseBody)
}

func TestUpdateFunction(t *testing.T) {
Expand Down Expand Up @@ -140,70 +143,149 @@ func TestUpdateFunction(t *testing.T) {
// tfFunctionName := terraform.Output(t, terraformOptions, "function_name")
// assert.Equal(t, functionName, tfFunctionName)

// // validate our function deployed
// host, err := getDefaultHost(projId)
// if err != nil {
// t.Fatal(err)
// }
// validate our function deployed
host, err := getDefaultHost(projId)
if err != nil {
t.Fatal(err)
}

// http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 30, 3*time.Second, validateResponseBody)
http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 10, 3*time.Second, validateResponseBody)
}

// func TestValidFunctionWithSecret(t *testing.T) {
// t.Parallel()

// // create org
// orgId, _, err := createOrg()
// if err != nil {
// t.Fatal("failed to create org")
// }

// // create project
// projId, _, err := createProj(orgId)
// if err != nil {
// t.Fatal("failed to create project")
// }

// // define a project name and validate it in the response
// functionName := uuid.NewString()
// moduleName := "./modules/single_function"

// // copy provider.tf
// defer os.Remove(fmt.Sprintf("%s/provider.tf", moduleName))
// err = files.CopyFile("./modules/provider.tf", fmt.Sprintf("%s/provider.tf", moduleName))
// if err != nil {
// t.Fatal("failed to copy provider file")
// }

// defer func() {
// if err := cleanupTerraformFiles(moduleName); err != nil {
// t.Logf("Warning: Failed to clean up Terraform files: %v", err)
// }
// }()

// terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
// TerraformDir: moduleName,
// Vars: map[string]interface{}{
// "project_id": projId,
// "function_name": functionName,
// },
// })

// defer deleteOrg(orgId)
// defer deleteProj(projId)
// defer terraform.Destroy(t, terraformOptions)

// terraform.InitAndApply(t, terraformOptions)

// // validate output
// // tfFunctionName := terraform.Output(t, terraformOptions, "function_name")
// // assert.Equal(t, functionName, tfFunctionName)

// // validate our function deployed
// host, err := getDefaultHost(projId)
// if err != nil {
// t.Fatal(err)
// }

// http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 30, 3*time.Second, validateResponseBody)
// }
func TestValidFunctionWithSecret(t *testing.T) {
t.Parallel()

// create org
orgId, _, err := createOrg()
if err != nil {
t.Fatal("failed to create org")
}

// create project
projId, _, err := createProj(orgId)
if err != nil {
t.Fatal("failed to create project")
}

// create secret
secretName := randomSecretName()
_, secretRef, err := createSecretEnv(projId, secretName)
if err != nil {
t.Fatal("failed to create project secret")
}

// define a project name and validate it in the response
functionName := uuid.NewString()
moduleName := "./modules/single_function_with_secret"

// copy provider.tf
defer os.Remove(fmt.Sprintf("%s/provider.tf", moduleName))
err = files.CopyFile("./modules/provider.tf", fmt.Sprintf("%s/provider.tf", moduleName))
if err != nil {
t.Fatal("failed to copy provider file")
}

defer func() {
if err := cleanupTerraformFiles(moduleName); err != nil {
t.Logf("Warning: Failed to clean up Terraform files: %v", err)
}
}()

terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: moduleName,
Vars: map[string]interface{}{
"project_id": projId,
"function_name": functionName,
"secret_reference": secretRef,
},
})

defer deleteOrg(orgId)
defer deleteProj(projId)
defer terraform.Destroy(t, terraformOptions)

terraform.InitAndApply(t, terraformOptions)

// validate output
// tfFunctionName := terraform.Output(t, terraformOptions, "function_name")
// assert.Equal(t, functionName, tfFunctionName)

// validate our function deployed
host, err := getDefaultHost(projId)
if err != nil {
t.Fatal(err)
}

http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 10, 3*time.Second, validateResponseBody)

// TODO: validate the env var in the response
}

func TestValidFunctionWithSecretDatasource(t *testing.T) {
t.Parallel()

// create org
orgId, _, err := createOrg()
if err != nil {
t.Fatal("failed to create org")
}

// create project
projId, _, err := createProj(orgId)
if err != nil {
t.Fatal("failed to create project")
}

// create secret
secretName := randomSecretName()
_, _, err = createSecretEnv(projId, secretName)
if err != nil {
t.Fatal("failed to create project secret")
}

// define a project name and validate it in the response
functionName := uuid.NewString()
moduleName := "./modules/single_function_with_secret_datasource"

// copy provider.tf
defer os.Remove(fmt.Sprintf("%s/provider.tf", moduleName))
err = files.CopyFile("./modules/provider.tf", fmt.Sprintf("%s/provider.tf", moduleName))
if err != nil {
t.Fatal("failed to copy provider file")
}

defer func() {
if err := cleanupTerraformFiles(moduleName); err != nil {
t.Logf("Warning: Failed to clean up Terraform files: %v", err)
}
}()

terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: moduleName,
Vars: map[string]interface{}{
"project_id": projId,
"function_name": functionName,
"secret_name": secretName,
},
})

defer deleteOrg(orgId)
defer deleteProj(projId)
defer terraform.Destroy(t, terraformOptions)

terraform.InitAndApply(t, terraformOptions)

// validate output
// tfFunctionName := terraform.Output(t, terraformOptions, "function_name")
// assert.Equal(t, functionName, tfFunctionName)

// validate our function deployed
host, err := getDefaultHost(projId)
if err != nil {
t.Fatal(err)
}

http_helper.HttpGetWithRetryWithCustomValidation(t, fmt.Sprintf("https://%s/", host), nil, 10, 3*time.Second, validateResponseBody)

// TODO: validate the env var in the response
}
5 changes: 2 additions & 3 deletions tests/qernal_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package tests
import (
"fmt"
"os"
"strings"
"testing"

"github.com/google/uuid"
Expand All @@ -25,7 +24,7 @@ func TestEnvironmentSecret(t *testing.T) {
t.Fatal("Failed to create project")
}

secretName := strings.ToUpper(randomSecretName())
secretName := randomSecretName()
secretValue := uuid.NewString()

moduleName := "./modules/environment_secret"
Expand Down Expand Up @@ -78,7 +77,7 @@ func TestRegistrySecret(t *testing.T) {
t.Fatal("Failed to create project")
}

secretName := strings.ToUpper(randomSecretName())
secretName := randomSecretName()
registryUrl := "ghcr.io"
authToken := randomSecretName()

Expand Down

0 comments on commit bb9518c

Please sign in to comment.