...

Source file src/edge-infra.dev/test/e2e/datasync/encryption/encrypt_test.go

Documentation: edge-infra.dev/test/e2e/datasync/encryption

     1  package encryption
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"net/url"
    10  	"slices"
    11  	"testing"
    12  	"time"
    13  
    14  	apiclient "edge-infra.dev/pkg/edge/api/client"
    15  	"edge-infra.dev/pkg/edge/api/graph/model"
    16  	"edge-infra.dev/pkg/edge/constants"
    17  	"edge-infra.dev/pkg/edge/edgeencrypt"
    18  	"edge-infra.dev/pkg/edge/info"
    19  	"edge-infra.dev/pkg/lib/gcp/secretmanager"
    20  	"edge-infra.dev/test/f2"
    21  	"edge-infra.dev/test/f2/x/bslauth"
    22  	"edge-infra.dev/test/f2/x/ktest"
    23  
    24  	"github.com/shurcooL/graphql"
    25  	"gotest.tools/v3/assert"
    26  	"gotest.tools/v3/poll"
    27  
    28  	corev1 "k8s.io/api/core/v1"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  )
    31  
    32  func TestEncryption(t *testing.T) {
    33  	var k *ktest.K8s
    34  	var edgeUser bslauth.User
    35  	var encryptedOutput string
    36  	var edgeInfo *info.EdgeInfo
    37  	portForward := ktest.PortForward{Namespace: edgeencrypt.EncryptionName}
    38  	feature := f2.NewFeature("Encryption E2E Test").
    39  		Setup("Initial setup", func(ctx f2.Context, t *testing.T) f2.Context {
    40  			k = ktest.FromContextT(ctx, t)
    41  			auth, err := bslauth.FromContext(ctx)
    42  			assert.NilError(t, err)
    43  
    44  			edgeUser = auth.User(bslauth.BannerAdmin)
    45  			if !valid(&edgeUser) {
    46  				t.Fatalf("Invalid edge user: %v", edgeUser)
    47  				return ctx
    48  			}
    49  
    50  			edgeInfo, err = info.FromClient(ctx, k.Client)
    51  			assert.NilError(t, err)
    52  			return ctx
    53  		}).
    54  		Test("Workload App", func(ctx f2.Context, t *testing.T) f2.Context {
    55  			creds := apiclient.WithCredentials(edgeUser.Username, edgeUser.Password, edgeUser.Org)
    56  			client, err := apiclient.New(creds, apiclient.WithBaseURL(edgeInfo.EdgeAPIEndpoint))
    57  			assert.NilError(t, err)
    58  
    59  			type helmWorkloads struct {
    60  				Name      string `graphql:"name"`
    61  				Namespace string `graphql:"namespace"`
    62  			}
    63  			var q struct {
    64  				HelmWorkloads []helmWorkloads `graphql:"helmWorkloads(clusterEdgeId: $clusterEdgeId)"`
    65  			}
    66  			err = client.Query(ctx, &q, map[string]any{
    67  				"clusterEdgeId": graphql.String(edgeInfo.ClusterEdgeID),
    68  			})
    69  			assert.NilError(t, err)
    70  
    71  			workloadFound := slices.IndexFunc(q.HelmWorkloads, func(w helmWorkloads) bool {
    72  				return w.Name == DefaultWorkload && w.Namespace == DefaultWorkload
    73  			})
    74  
    75  			if workloadFound <= 0 {
    76  				createHelmRelease(ctx, t, edgeInfo, client)
    77  			}
    78  
    79  			return ctx
    80  		}).
    81  		Setup("Datasync Sparrow PortForwarding", portForward.Forward("sparrow", 8080)).
    82  		Test("Health Check", func(ctx f2.Context, t *testing.T) f2.Context {
    83  			addr := portForward.Retrieve(t)
    84  			response, err := http.Get(fmt.Sprintf("http://%s/health", addr))
    85  			assert.NilError(t, err)
    86  			body, err := io.ReadAll(response.Body)
    87  			defer response.Body.Close()
    88  			assert.NilError(t, err)
    89  			assert.Equal(t, string(body), "ok")
    90  			return ctx
    91  		}).
    92  		Test("Encrypt Data", func(ctx f2.Context, t *testing.T) f2.Context {
    93  			addr := portForward.Retrieve(t)
    94  
    95  			s := &corev1.Secret{
    96  				TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Secret"},
    97  				ObjectMeta: metav1.ObjectMeta{
    98  					Name:      fmt.Sprintf(edgeencrypt.EncryptionBearerToken, DefaultChannelName),
    99  					Namespace: DefaultWorkload,
   100  				},
   101  			}
   102  
   103  			// poll for secret
   104  			k.WaitOn(t, k.ObjExists(s), poll.WithDelay(2*time.Second), poll.WithTimeout(3*time.Minute))
   105  
   106  			body, err := json.Marshal(tlog)
   107  			assert.NilError(t, err)
   108  
   109  			req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/v1/encrypt", addr), bytes.NewReader(body))
   110  			assert.NilError(t, err)
   111  
   112  			token := string(s.Data["token"])
   113  			req.Header.Set("Authorization", "Bearer "+token)
   114  			req.Header.Set("Content-Type", "application/json")
   115  
   116  			resp, err := http.DefaultClient.Do(req)
   117  			assert.NilError(t, err)
   118  			defer resp.Body.Close()
   119  
   120  			encryptedData, err := io.ReadAll(resp.Body)
   121  			assert.NilError(t, err)
   122  			assert.Equal(t, http.StatusOK, resp.StatusCode)
   123  			encryptedOutput = string(encryptedData)
   124  			return ctx
   125  		}).
   126  		Test("Decrypt Data", func(ctx f2.Context, t *testing.T) f2.Context {
   127  			uri, err := url.Parse(edgeInfo.EdgeAPIEndpoint)
   128  			assert.NilError(t, err)
   129  
   130  			addr := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host)
   131  
   132  			encryptedData := encryptedOutput
   133  			assert.Assert(t, encryptedData != "", "Encrypted data is missing")
   134  
   135  			decryptURL := fmt.Sprintf("%s/crypto/v1/decrypt/%s", addr, DefaultChannelName)
   136  
   137  			req, err := http.NewRequest(http.MethodPost, decryptURL, bytes.NewReader([]byte(encryptedData)))
   138  			assert.NilError(t, err)
   139  
   140  			sm, err := secretmanager.NewWithOptions(ctx, edgeInfo.ForemanProjectID)
   141  			assert.NilError(t, err)
   142  
   143  			secret, err := sm.GetLatestSecretValue(ctx, edgeencrypt.DecryptionTokenSecretManager)
   144  			assert.NilError(t, err)
   145  
   146  			var s edgeencrypt.Token
   147  
   148  			err = json.Unmarshal(secret, &s)
   149  			assert.NilError(t, err)
   150  
   151  			req.Header.Set("Authorization", "Bearer "+s.BearerToken)
   152  			req.Header.Set("Content-Type", "text/plain")
   153  
   154  			resp, err := http.DefaultClient.Do(req)
   155  			assert.NilError(t, err)
   156  			defer resp.Body.Close()
   157  
   158  			decryptedData, err := io.ReadAll(resp.Body)
   159  			assert.NilError(t, err)
   160  			assert.Equal(t, http.StatusOK, resp.StatusCode)
   161  
   162  			t.Logf("Decrypted Data: %s", string(decryptedData))
   163  
   164  			return ctx
   165  		}).
   166  		Feature()
   167  	f.Test(t, feature)
   168  }
   169  
   170  func createHelmRelease(ctx f2.Context, t *testing.T, edgeInfo *info.EdgeInfo, client *apiclient.EdgeClient) {
   171  	cv := string(configValues)
   172  	installationType := model.WorkloadInstallationTypeServer
   173  	type helmReleasePayload struct {
   174  		model.HelmReleasePayload
   175  	}
   176  	hrp := helmReleasePayload{
   177  		HelmReleasePayload: model.HelmReleasePayload{
   178  			Name:             DefaultWorkload,
   179  			Secret:           constants.HelmRead,
   180  			HelmRepository:   constants.NCRCharts,
   181  			HelmChart:        DefaultWorkload,
   182  			Version:          "6.2.2",
   183  			Namespace:        DefaultWorkload,
   184  			ClusterEdgeID:    &edgeInfo.ClusterEdgeID,
   185  			ConfigValues:     &cv,
   186  			InstallationType: &installationType,
   187  		},
   188  	}
   189  
   190  	var mutation struct {
   191  		CreateHelmRelease bool `graphql:"createHelmRelease(payload: $helmReleasePayload)"`
   192  	}
   193  	variables := map[string]interface{}{"helmReleasePayload": hrp}
   194  
   195  	err := client.Mutate(ctx, &mutation, variables)
   196  	assert.NilError(t, err)
   197  }
   198  
   199  func valid(user *bslauth.User) bool {
   200  	return user.Username != "" && user.Password != "" && user.Org != ""
   201  }
   202  

View as plain text