Alexander Belanger 5 лет назад
Родитель
Сommit
fb7eb4f3c9

+ 0 - 1
internal/forms/candidate_test.go

@@ -1 +0,0 @@
-package forms_test

+ 0 - 194
internal/forms/cluster.go

@@ -438,197 +438,3 @@ func (rcf *ResolveClusterForm) buildCluster() (*models.Cluster, error) {
 
 	return cluster, nil
 }
-
-// // Resolver exposes an interface for resolving a ClusterCandidate.
-// // So that actions can be chained together, a pointer to a cluster can be
-// // used -- if this points to nil, a new cluster is created
-// type Resolver interface {
-// 	PopulateServiceAccount(repo repository.ClusterRepository) error
-// }
-
-// // ClusterResolver is the base type for resolving a ClusterCandidate
-// type ClusterResolver struct {
-// 	ClusterCandidateID uint `json:"cluster_candidate_id" form:"required"`
-// 	ProjectID uint `json:"project_id" form:"required"`
-// 	Cluster            *models.Cluster
-// 	ClusterCandidate   *models.ClusterCandidate
-// }
-
-// // PopulateServiceAccount will create a service account if it does not exist,
-// // or will append a new cluster given by a ServiceAccountCandidate to the
-// // ServiceAccount
-// func (cr *ClusterResolver) PopulateServiceAccount(
-// 	repo repository.ClusterRepository,
-// ) error {
-// 	var err error
-// 	id := cr.ClusterCandidateID
-
-// 	if cr.ClusterCandidate == nil {
-// 		cr.ClusterCandidate, err = repo.ReadClusterCandidate(id)
-
-// 		if err != nil {
-// 			return err
-// 		}
-// 	}
-
-// 	rawConf, err := kubernetes.GetRawConfigFromBytes(cr.ClusterCandidate.Kubeconfig)
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	context := rawConf.Contexts[rawConf.CurrentContext]
-
-// 	authInfoName := context.AuthInfo
-// 	authInfo := rawConf.AuthInfos[authInfoName]
-
-// 	clusterName := context.Cluster
-// 	cluster := rawConf.Clusters[clusterName]
-
-// 	cr.Cluster = models.Cluster{
-// 		ProjectID: cr.ProjectID,
-// 		Name:                  clusterName,
-// 		Server:                cluster.Server,
-// 		LocationOfOrigin:      cluster.ClusterLocationOfOrigin,
-// 		TLSServerName:         cluster.TLSServerName,
-// 		InsecureSkipTLSVerify: cluster.InsecureSkipTLSVerify,
-// 	}
-
-// 	if len(cr.Cluster.CertificateAuthorityData) > 0 {
-// 		cr.Cluster.CertificateAuthorityData = cluster.CertificateAuthorityData
-// 	}
-
-// 	// if auth mechanism is local, just write the kubeconfig and return: rest of config is
-// 	// unnecessary
-// 	if sar.SACandidate.Integration == models.Local && len(sar.SACandidate.Kubeconfig) > 0 {
-// 		sar.SA.Kubeconfig = sar.SACandidate.Kubeconfig
-// 		return nil
-// 	}
-
-// 	if len(authInfo.ClientCertificateData) > 0 {
-// 		sar.SA.ClientCertificateData = authInfo.ClientCertificateData
-// 	}
-
-// 	if len(authInfo.ClientKeyData) > 0 {
-// 		sar.SA.ClientKeyData = authInfo.ClientKeyData
-// 	}
-
-// 	if len(authInfo.Token) > 0 {
-// 		sar.SA.Token = []byte(authInfo.Token)
-// 	}
-
-// 	if len(authInfo.Username) > 0 {
-// 		sar.SA.Username = []byte(authInfo.Username)
-// 	}
-
-// 	if len(authInfo.Password) > 0 {
-// 		sar.SA.Password = []byte(authInfo.Password)
-// 	}
-
-// 	if authInfo.AuthProvider != nil && authInfo.AuthProvider.Name == "oidc" {
-// 		if url, ok := authInfo.AuthProvider.Config["idp-issuer-url"]; ok {
-// 			sar.SA.OIDCIssuerURL = []byte(url)
-// 		}
-
-// 		if clientID, ok := authInfo.AuthProvider.Config["client-id"]; ok {
-// 			sar.SA.OIDCClientID = []byte(clientID)
-// 		}
-
-// 		if clientSecret, ok := authInfo.AuthProvider.Config["client-secret"]; ok {
-// 			sar.SA.OIDCClientSecret = []byte(clientSecret)
-// 		}
-
-// 		if caData, ok := authInfo.AuthProvider.Config["idp-certificate-authority-data"]; ok {
-// 			// based on the implementation, the oidc plugin expects the data to be base64 encoded,
-// 			// which means we will not decode it here
-// 			// reference: https://github.com/kubernetes/kubernetes/blob/9dfb4c876bfca7a5ae84259fae2bc337ed90c2d7/staging/src/k8s.io/client-go/plugin/pkg/client/auth/oidc/oidc.go#L135
-// 			sar.SA.OIDCCertificateAuthorityData = []byte(caData)
-// 		}
-
-// 		if idToken, ok := authInfo.AuthProvider.Config["id-token"]; ok {
-// 			sar.SA.OIDCIDToken = []byte(idToken)
-// 		}
-
-// 		if refreshToken, ok := authInfo.AuthProvider.Config["refresh-token"]; ok {
-// 			sar.SA.OIDCRefreshToken = []byte(refreshToken)
-// 		}
-// 	}
-
-// 	return nil
-// }
-
-// // ClientKeyDataAction contains the base64 encoded cluster key data
-// type ClientKeyDataAction struct {
-// 	*ClusterResolver
-// 	ClientKeyData string `json:"client_key_data" form:"required"`
-// }
-
-// // OIDCIssuerDataAction contains the base64 encoded IDP issuer CA data
-// type OIDCIssuerDataAction struct {
-// 	*ClusterResolver
-// 	OIDCIssuerCAData string `json:"oidc_idp_issuer_ca_data" form:"required"`
-// }
-
-// // PopulateServiceAccount will add OIDC issuer CA data to a ServiceAccount
-// func (oida *OIDCIssuerDataAction) PopulateServiceAccount(
-// 	repo repository.ClusterRepository,
-// ) error {
-// 	err := oida.ServiceAccountActionResolver.PopulateServiceAccount(repo)
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	// based on the implementation, the oidc plugin expects the data to be base64 encoded,
-// 	// which means we will not decode it here
-// 	// reference: https://github.com/kubernetes/kubernetes/blob/9dfb4c876bfca7a5ae84259fae2bc337ed90c2d7/staging/src/k8s.io/client-go/plugin/pkg/client/auth/oidc/oidc.go#L135
-// 	oida.ServiceAccountActionResolver.SA.OIDCCertificateAuthorityData = []byte(oida.OIDCIssuerCAData)
-
-// 	return nil
-// }
-
-// // GCPKeyDataAction contains the GCP key data
-// type GCPKeyDataAction struct {
-// 	*ClusterResolver
-// 	GCPKeyData string `json:"gcp_key_data" form:"required"`
-// }
-
-// // PopulateServiceAccount will add GCP key data to a ServiceAccount
-// func (gkda *GCPKeyDataAction) PopulateServiceAccount(
-// 	repo repository.ClusterRepository,
-// ) error {
-// 	err := gkda.ServiceAccountActionResolver.PopulateServiceAccount(repo)
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	gkda.ServiceAccountActionResolver.SA.GCPKeyData = []byte(gkda.GCPKeyData)
-
-// 	return nil
-// }
-
-// // AWSDataAction contains the AWS data (access id, key)
-// type AWSDataAction struct {
-// 	*ClusterResolver
-// 	AWSAccessKeyID     string `json:"aws_access_key_id" form:"required"`
-// 	AWSSecretAccessKey string `json:"aws_secret_access_key" form:"required"`
-// 	AWSClusterID       string `json:"aws_cluster_id" form:"required"`
-// }
-
-// // PopulateServiceAccount will add GCP key data to a ServiceAccount
-// func (akda *AWSDataAction) PopulateServiceAccount(
-// 	repo repository.ClusterRepository,
-// ) error {
-// 	err := akda.ServiceAccountActionResolver.PopulateServiceAccount(repo)
-
-// 	if err != nil {
-// 		return err
-// 	}
-
-// 	akda.ServiceAccountActionResolver.SA.AWSAccessKeyID = []byte(akda.AWSAccessKeyID)
-// 	akda.ServiceAccountActionResolver.SA.AWSSecretAccessKey = []byte(akda.AWSSecretAccessKey)
-// 	akda.ServiceAccountActionResolver.SA.AWSClusterID = []byte(akda.AWSClusterID)
-
-// 	return nil
-// }

+ 617 - 517
internal/forms/cluster_test.go

@@ -1,577 +1,677 @@
 package forms_test
 
 import (
-	"encoding/base64"
 	"testing"
 
+	"github.com/go-test/deep"
 	"github.com/porter-dev/porter/internal/forms"
-	"github.com/porter-dev/porter/internal/kubernetes"
 	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository/test"
-)
-
-func TestPopulateServiceAccountBasic(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClusterCAWithData), false)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
-
-	// create a new form
-	form := forms.ServiceAccountActionResolver{
-		ServiceAccountCandidateID: 1,
-	}
-
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.SA)
-	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
-		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
-			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
-	}
-
-	if sa.Integration != "x509" {
-		t.Errorf("service account auth mechanism is not x509")
-	}
-
-	if string(sa.ClientCertificateData) != string(decodedStr) {
-		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
-			string(sa.ClientCertificateData), string(decodedStr))
-	}
+	"gorm.io/gorm"
 
-	if string(sa.ClientKeyData) != string(decodedStr) {
-		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
-			string(sa.ClientKeyData), string(decodedStr))
-	}
-}
-
-func TestPopulateServiceAccountClusterDataAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClusterCAWithoutData), false)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
-
-	// create a new form
-	form := forms.ClusterCADataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		ClusterCAData: "LS0tLS1CRUdJTiBDRVJ=",
-	}
-
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
-		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
-			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
-	}
-
-	if sa.Integration != "x509" {
-		t.Errorf("service account auth mechanism is not x509")
-	}
-
-	if string(sa.ClientCertificateData) != string(decodedStr) {
-		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
-			string(sa.ClientCertificateData), string(decodedStr))
-	}
-
-	if string(sa.ClientKeyData) != string(decodedStr) {
-		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
-			string(sa.ClientKeyData), string(decodedStr))
-	}
-}
-
-func TestPopulateServiceAccountClusterLocalhostAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClusterLocalhost), false)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
-
-	// create a new form
-	form := forms.ClusterLocalhostAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		ClusterHostname: "host.docker.internal",
-	}
-
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if sa.Clusters[0].Server != "https://host.docker.internal:30000" {
-		t.Errorf("service account cluster server is incorrect: expected %s, got %s\n",
-			"https://host.docker.internal:30000", sa.Clusters[0].Server)
-	}
-
-	if sa.Integration != "x509" {
-		t.Errorf("service account auth mechanism is not x509")
-	}
-
-	if string(sa.ClientCertificateData) != string(decodedStr) {
-		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
-			string(sa.ClientCertificateData), string(decodedStr))
-	}
-
-	if string(sa.ClientKeyData) != string(decodedStr) {
-		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
-			string(sa.ClientKeyData), string(decodedStr))
-	}
-}
-
-func TestPopulateServiceAccountClientCertAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClientWithoutCertData), false)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
-
-	// create a new form
-	form := forms.ClientCertDataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		ClientCertData: "LS0tLS1CRUdJTiBDRVJ=",
-	}
-
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
-		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
-			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
-	}
-
-	if sa.Integration != "x509" {
-		t.Errorf("service account auth mechanism is not x509")
-	}
-
-	if string(sa.ClientCertificateData) != string(decodedStr) {
-		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
-			string(sa.ClientCertificateData), string(decodedStr))
-	}
-
-	if string(sa.ClientKeyData) != string(decodedStr) {
-		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
-			string(sa.ClientKeyData), string(decodedStr))
-	}
-}
-
-func TestPopulateServiceAccountClientCertAndKeyActions(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClientWithoutCertAndKeyData), false)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
-
-	// create a new form
-	form := forms.ClientCertDataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		ClientCertData: "LS0tLS1CRUdJTiBDRVJ=",
-	}
-
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	keyForm := forms.ClientKeyDataAction{
-		ServiceAccountActionResolver: form.ServiceAccountActionResolver,
-		ClientKeyData:                "LS0tLS1CRUdJTiBDRVJ=",
-	}
-
-	err = keyForm.PopulateServiceAccount(repo.ServiceAccount)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	sa, err := repo.ServiceAccount.CreateServiceAccount(keyForm.ServiceAccountActionResolver.SA)
-	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
-		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
-			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
-	}
-
-	if sa.Integration != "x509" {
-		t.Errorf("service account auth mechanism is not x509")
-	}
-
-	if string(sa.ClientCertificateData) != string(decodedStr) {
-		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
-			string(sa.ClientCertificateData), string(decodedStr))
-	}
-
-	if string(sa.ClientKeyData) != string(decodedStr) {
-		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
-			string(sa.ClientKeyData), string(decodedStr))
-	}
-}
-
-func TestPopulateServiceAccountTokenDataAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-	tokenData := "abcdefghijklmnop"
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(BearerTokenWithoutData), false)
+	ints "github.com/porter-dev/porter/internal/models/integrations"
+)
 
-	if err != nil {
-		t.Fatalf("%v\n", err)
+func TestClusterLocal(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./cluster_local.db",
 	}
 
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
+	setupTestEnv(tester, t)
+	initUser(tester, t)
+	initProject(tester, t)
+	defer cleanup(tester, t)
 
-	// create a new form
-	form := forms.TokenDataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		TokenData: tokenData,
+	// create cluster candidate
+	ccForm := &forms.CreateClusterCandidatesForm{
+		ProjectID:  tester.initProjects[0].ID,
+		Kubeconfig: ClusterCAWithData,
+		IsLocal:    true,
 	}
 
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
+	ccs, err := ccForm.ToClusterCandidates(true)
 
 	if err != nil {
 		t.Fatalf("%v\n", err)
 	}
 
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if sa.Integration != models.Bearer {
-		t.Errorf("service account auth mechanism is not %s\n", models.Bearer)
-	}
-
-	if string(sa.Token) != tokenData {
-		t.Errorf("service account token data is wrong: expected %s, got %s\n",
-			tokenData, sa.Token)
-	}
-}
-
-func TestPopulateServiceAccountGCPKeyDataAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-	gcpKeyData := []byte(`{"key": "data"}`)
+	var cc *models.ClusterCandidate
 
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
+	for _, _cc := range ccs {
+		cc, err = tester.repo.Cluster.CreateClusterCandidate(_cc)
 
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(GCPPlugin), false)
+		if err != nil {
+			t.Fatalf("%v\n", err)
+		}
 
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
+		cc, err = tester.repo.Cluster.ReadClusterCandidate(cc.ID)
 
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+		if err != nil {
+			t.Fatalf("%v\n", err)
+		}
 	}
 
-	// create a new form
-	form := forms.GCPKeyDataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		GCPKeyData: string(gcpKeyData),
+	form := &forms.ResolveClusterForm{
+		Resolver:           &models.ClusterResolverAll{},
+		ClusterCandidateID: cc.ID,
+		ProjectID:          tester.initProjects[0].ID,
+		UserID:             tester.initUsers[0].ID,
 	}
 
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
+	// resolve integration (should be kube with local)
+	err = form.ResolveIntegration(*tester.repo)
 
 	if err != nil {
 		t.Fatalf("%v\n", err)
 	}
 
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
+	expIntegration := &ints.KubeIntegration{
+		Mechanism:  ints.KubeLocal,
+		UserID:     tester.initUsers[0].ID,
+		ProjectID:  tester.initProjects[0].ID,
+		Kubeconfig: cc.Kubeconfig,
 	}
 
-	if sa.Integration != models.GCP {
-		t.Errorf("service account auth mechanism is not %s\n", models.GCP)
-	}
-
-	if string(sa.GCPKeyData) != string(gcpKeyData) {
-		t.Errorf("service account token data is wrong: expected %s, got %s\n",
-			string(sa.GCPKeyData), string(gcpKeyData))
-	}
-}
-
-func TestPopulateServiceAccountAWSKeyDataAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
-
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(AWSEKSGetTokenExec), false)
+	// make sure integration is equal, read integration from DB
+	gotIntegration, err := tester.repo.KubeIntegration.ReadKubeIntegration(form.IntegrationID)
 
 	if err != nil {
 		t.Fatalf("%v\n", err)
 	}
 
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
+	// reset got integration model
+	gotIntegration.Model = gorm.Model{}
 
-	// create a new form
-	form := forms.AWSDataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		AWSAccessKeyID:     "ALSDKJFADSF",
-		AWSSecretAccessKey: "ASDLFKJALSDKFJ",
-		AWSClusterID:       "cluster-test",
+	if diff := deep.Equal(expIntegration, gotIntegration); diff != nil {
+		t.Errorf("incorrect integration")
+		t.Error(diff)
 	}
 
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
+	// resolve cluster
+	gotCluster, err := form.ResolveCluster(*tester.repo)
 
 	if err != nil {
 		t.Fatalf("%v\n", err)
 	}
 
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if sa.Integration != models.AWS {
-		t.Errorf("service account auth mechanism is not %s\n", models.AWS)
+	expCluster := &models.Cluster{
+		AuthMechanism:            models.Local,
+		ProjectID:                1,
+		Name:                     "cluster-test",
+		Server:                   "https://localhost",
+		KubeIntegrationID:        1,
+		CertificateAuthorityData: []byte("-----BEGIN CER"),
 	}
 
-	if string(sa.AWSAccessKeyID) != "ALSDKJFADSF" {
-		t.Errorf("service account aws access key id is wrong: expected %s, got %s\n",
-			"ALSDKJFADSF", sa.AWSAccessKeyID)
-	}
+	gotCluster.Model = gorm.Model{}
 
-	if string(sa.AWSSecretAccessKey) != "ASDLFKJALSDKFJ" {
-		t.Errorf("service account aws access secret key is wrong: expected %s, got %s\n",
-			"ASDLFKJALSDKFJ", sa.AWSSecretAccessKey)
-	}
-
-	if string(sa.AWSClusterID) != "cluster-test" {
-		t.Errorf("service account aws cluster id is wrong: expected %s, got %s\n",
-			"cluster-test", sa.AWSClusterID)
+	if diff := deep.Equal(expCluster, gotCluster); diff != nil {
+		t.Errorf("incorrect cluster")
+		t.Error(diff)
 	}
 }
 
-func TestPopulateServiceAccountOIDCAction(t *testing.T) {
-	// create the in-memory repository
-	repo := test.NewRepository(true)
-
-	// create a new project
-	repo.Project.CreateProject(&models.Project{
-		Name: "test-project",
-	})
+// func TestPopulateServiceAccountBasic(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
 
-	// create a ServiceAccountCandidate from a kubeconfig
-	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(OIDCAuthWithoutData), false)
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
 
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	for _, saCandidate := range saCandidates {
-		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
-	}
-
-	// create a new form
-	form := forms.OIDCIssuerDataAction{
-		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
-			ServiceAccountCandidateID: 1,
-		},
-		OIDCIssuerCAData: "LS0tLS1CRUdJTiBDRVJ=",
-	}
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClusterCAWithData), false)
 
-	err = form.PopulateServiceAccount(repo.ServiceAccount)
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
 
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
-
-	if len(sa.Clusters) != 1 {
-		t.Fatalf("cluster not written\n")
-	}
-
-	if sa.Clusters[0].ServiceAccountID != 1 {
-		t.Errorf("service account ID of joined cluster is not 1")
-	}
-
-	if sa.Integration != models.OIDC {
-		t.Errorf("service account auth mechanism is not %s\n", models.OIDC)
-	}
-
-	if string(sa.OIDCCertificateAuthorityData) != "LS0tLS1CRUdJTiBDRVJ=" {
-		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
-			string(sa.OIDCCertificateAuthorityData), "LS0tLS1CRUdJTiBDRVJ=")
-	}
-}
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.ServiceAccountActionResolver{
+// 		ServiceAccountCandidateID: 1,
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.SA)
+// 	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
+// 		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
+// 			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
+// 	}
+
+// 	if sa.Integration != "x509" {
+// 		t.Errorf("service account auth mechanism is not x509")
+// 	}
+
+// 	if string(sa.ClientCertificateData) != string(decodedStr) {
+// 		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientCertificateData), string(decodedStr))
+// 	}
+
+// 	if string(sa.ClientKeyData) != string(decodedStr) {
+// 		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientKeyData), string(decodedStr))
+// 	}
+// }
+
+// func TestPopulateServiceAccountClusterDataAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClusterCAWithoutData), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.ClusterCADataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		ClusterCAData: "LS0tLS1CRUdJTiBDRVJ=",
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+// 	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
+// 		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
+// 			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
+// 	}
+
+// 	if sa.Integration != "x509" {
+// 		t.Errorf("service account auth mechanism is not x509")
+// 	}
+
+// 	if string(sa.ClientCertificateData) != string(decodedStr) {
+// 		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientCertificateData), string(decodedStr))
+// 	}
+
+// 	if string(sa.ClientKeyData) != string(decodedStr) {
+// 		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientKeyData), string(decodedStr))
+// 	}
+// }
+
+// func TestPopulateServiceAccountClusterLocalhostAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClusterLocalhost), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.ClusterLocalhostAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		ClusterHostname: "host.docker.internal",
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+// 	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if sa.Clusters[0].Server != "https://host.docker.internal:30000" {
+// 		t.Errorf("service account cluster server is incorrect: expected %s, got %s\n",
+// 			"https://host.docker.internal:30000", sa.Clusters[0].Server)
+// 	}
+
+// 	if sa.Integration != "x509" {
+// 		t.Errorf("service account auth mechanism is not x509")
+// 	}
+
+// 	if string(sa.ClientCertificateData) != string(decodedStr) {
+// 		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientCertificateData), string(decodedStr))
+// 	}
+
+// 	if string(sa.ClientKeyData) != string(decodedStr) {
+// 		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientKeyData), string(decodedStr))
+// 	}
+// }
+
+// func TestPopulateServiceAccountClientCertAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClientWithoutCertData), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.ClientCertDataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		ClientCertData: "LS0tLS1CRUdJTiBDRVJ=",
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+// 	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
+// 		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
+// 			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
+// 	}
+
+// 	if sa.Integration != "x509" {
+// 		t.Errorf("service account auth mechanism is not x509")
+// 	}
+
+// 	if string(sa.ClientCertificateData) != string(decodedStr) {
+// 		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientCertificateData), string(decodedStr))
+// 	}
+
+// 	if string(sa.ClientKeyData) != string(decodedStr) {
+// 		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientKeyData), string(decodedStr))
+// 	}
+// }
+
+// func TestPopulateServiceAccountClientCertAndKeyActions(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(ClientWithoutCertAndKeyData), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.ClientCertDataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		ClientCertData: "LS0tLS1CRUdJTiBDRVJ=",
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	keyForm := forms.ClientKeyDataAction{
+// 		ServiceAccountActionResolver: form.ServiceAccountActionResolver,
+// 		ClientKeyData:                "LS0tLS1CRUdJTiBDRVJ=",
+// 	}
+
+// 	err = keyForm.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(keyForm.ServiceAccountActionResolver.SA)
+// 	decodedStr, _ := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJ=")
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if string(sa.Clusters[0].CertificateAuthorityData) != string(decodedStr) {
+// 		t.Errorf("cluster ca data and input do not match: expected %s, got %s\n",
+// 			string(sa.Clusters[0].CertificateAuthorityData), string(decodedStr))
+// 	}
+
+// 	if sa.Integration != "x509" {
+// 		t.Errorf("service account auth mechanism is not x509")
+// 	}
+
+// 	if string(sa.ClientCertificateData) != string(decodedStr) {
+// 		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientCertificateData), string(decodedStr))
+// 	}
+
+// 	if string(sa.ClientKeyData) != string(decodedStr) {
+// 		t.Errorf("service account cert data and input do not match: expected %s, got %s\n",
+// 			string(sa.ClientKeyData), string(decodedStr))
+// 	}
+// }
+
+// func TestPopulateServiceAccountTokenDataAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+// 	tokenData := "abcdefghijklmnop"
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(BearerTokenWithoutData), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.TokenDataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		TokenData: tokenData,
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if sa.Integration != models.Bearer {
+// 		t.Errorf("service account auth mechanism is not %s\n", models.Bearer)
+// 	}
+
+// 	if string(sa.Token) != tokenData {
+// 		t.Errorf("service account token data is wrong: expected %s, got %s\n",
+// 			tokenData, sa.Token)
+// 	}
+// }
+
+// func TestPopulateServiceAccountGCPKeyDataAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+// 	gcpKeyData := []byte(`{"key": "data"}`)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(GCPPlugin), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.GCPKeyDataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		GCPKeyData: string(gcpKeyData),
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if sa.Integration != models.GCP {
+// 		t.Errorf("service account auth mechanism is not %s\n", models.GCP)
+// 	}
+
+// 	if string(sa.GCPKeyData) != string(gcpKeyData) {
+// 		t.Errorf("service account token data is wrong: expected %s, got %s\n",
+// 			string(sa.GCPKeyData), string(gcpKeyData))
+// 	}
+// }
+
+// func TestPopulateServiceAccountAWSKeyDataAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(AWSEKSGetTokenExec), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.AWSDataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		AWSAccessKeyID:     "ALSDKJFADSF",
+// 		AWSSecretAccessKey: "ASDLFKJALSDKFJ",
+// 		AWSClusterID:       "cluster-test",
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if sa.Integration != models.AWS {
+// 		t.Errorf("service account auth mechanism is not %s\n", models.AWS)
+// 	}
+
+// 	if string(sa.AWSAccessKeyID) != "ALSDKJFADSF" {
+// 		t.Errorf("service account aws access key id is wrong: expected %s, got %s\n",
+// 			"ALSDKJFADSF", sa.AWSAccessKeyID)
+// 	}
+
+// 	if string(sa.AWSSecretAccessKey) != "ASDLFKJALSDKFJ" {
+// 		t.Errorf("service account aws access secret key is wrong: expected %s, got %s\n",
+// 			"ASDLFKJALSDKFJ", sa.AWSSecretAccessKey)
+// 	}
+
+// 	if string(sa.AWSClusterID) != "cluster-test" {
+// 		t.Errorf("service account aws cluster id is wrong: expected %s, got %s\n",
+// 			"cluster-test", sa.AWSClusterID)
+// 	}
+// }
+
+// func TestPopulateServiceAccountOIDCAction(t *testing.T) {
+// 	// create the in-memory repository
+// 	repo := test.NewRepository(true)
+
+// 	// create a new project
+// 	repo.Project.CreateProject(&models.Project{
+// 		Name: "test-project",
+// 	})
+
+// 	// create a ServiceAccountCandidate from a kubeconfig
+// 	saCandidates, err := kubernetes.GetServiceAccountCandidates([]byte(OIDCAuthWithoutData), false)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	for _, saCandidate := range saCandidates {
+// 		repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+// 	}
+
+// 	// create a new form
+// 	form := forms.OIDCIssuerDataAction{
+// 		ServiceAccountActionResolver: &forms.ServiceAccountActionResolver{
+// 			ServiceAccountCandidateID: 1,
+// 		},
+// 		OIDCIssuerCAData: "LS0tLS1CRUdJTiBDRVJ=",
+// 	}
+
+// 	err = form.PopulateServiceAccount(repo.ServiceAccount)
+
+// 	if err != nil {
+// 		t.Fatalf("%v\n", err)
+// 	}
+
+// 	sa, err := repo.ServiceAccount.CreateServiceAccount(form.ServiceAccountActionResolver.SA)
+
+// 	if len(sa.Clusters) != 1 {
+// 		t.Fatalf("cluster not written\n")
+// 	}
+
+// 	if sa.Clusters[0].ServiceAccountID != 1 {
+// 		t.Errorf("service account ID of joined cluster is not 1")
+// 	}
+
+// 	if sa.Integration != models.OIDC {
+// 		t.Errorf("service account auth mechanism is not %s\n", models.OIDC)
+// 	}
+
+// 	if string(sa.OIDCCertificateAuthorityData) != "LS0tLS1CRUdJTiBDRVJ=" {
+// 		t.Errorf("service account key data and input do not match: expected %s, got %s\n",
+// 			string(sa.OIDCCertificateAuthorityData), "LS0tLS1CRUdJTiBDRVJ=")
+// 	}
+// }
 
 const ClusterCAWithData string = `
 apiVersion: v1

+ 358 - 0
internal/forms/helper_test.go

@@ -0,0 +1,358 @@
+package forms_test
+
+import (
+	"os"
+	"testing"
+
+	"github.com/porter-dev/porter/internal/adapter"
+	"github.com/porter-dev/porter/internal/config"
+	"github.com/porter-dev/porter/internal/models"
+	ints "github.com/porter-dev/porter/internal/models/integrations"
+	"github.com/porter-dev/porter/internal/repository"
+	"github.com/porter-dev/porter/internal/repository/gorm"
+)
+
+type tester struct {
+	repo         *repository.Repository
+	key          *[32]byte
+	dbFileName   string
+	initUsers    []*models.User
+	initProjects []*models.Project
+	initGRs      []*models.GitRepo
+	initClusters []*models.Cluster
+	initCCs      []*models.ClusterCandidate
+	initKIs      []*ints.KubeIntegration
+	initOIDCs    []*ints.OIDCIntegration
+	initOAuths   []*ints.OAuthIntegration
+	initGCPs     []*ints.GCPIntegration
+	initAWSs     []*ints.AWSIntegration
+}
+
+func setupTestEnv(tester *tester, t *testing.T) {
+	t.Helper()
+
+	db, err := adapter.New(&config.DBConf{
+		EncryptionKey: "__random_strong_encryption_key__",
+		SQLLite:       true,
+		SQLLitePath:   tester.dbFileName,
+	})
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	err = db.AutoMigrate(
+		&models.Project{},
+		&models.Role{},
+		&models.User{},
+		&models.Session{},
+		&models.GitRepo{},
+		&models.Cluster{},
+		&models.ClusterCandidate{},
+		&models.ClusterResolver{},
+		&ints.KubeIntegration{},
+		&ints.OIDCIntegration{},
+		&ints.OAuthIntegration{},
+		&ints.GCPIntegration{},
+		&ints.AWSIntegration{},
+		&ints.TokenCache{},
+	)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	var key [32]byte
+
+	for i, b := range []byte("__random_strong_encryption_key__") {
+		key[i] = b
+	}
+
+	tester.key = &key
+
+	tester.repo = gorm.NewRepository(db, &key)
+}
+
+func cleanup(tester *tester, t *testing.T) {
+	t.Helper()
+
+	// remove the created file file
+	os.Remove(tester.dbFileName)
+}
+
+func initUser(tester *tester, t *testing.T) {
+	t.Helper()
+
+	user := &models.User{
+		Email:    "example@example.com",
+		Password: "hello1234",
+	}
+
+	user, err := tester.repo.User.CreateUser(user)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initUsers = append(tester.initUsers, user)
+}
+
+func initProject(tester *tester, t *testing.T) {
+	t.Helper()
+
+	proj := &models.Project{
+		Name: "project-test",
+	}
+
+	proj, err := tester.repo.Project.CreateProject(proj)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initProjects = append(tester.initProjects, proj)
+}
+
+func initProjectRole(tester *tester, t *testing.T) {
+	t.Helper()
+
+	role := &models.Role{
+		Kind:      models.RoleAdmin,
+		UserID:    tester.initUsers[0].Model.ID,
+		ProjectID: tester.initProjects[0].Model.ID,
+	}
+
+	role, err := tester.repo.Project.CreateProjectRole(tester.initProjects[0], role)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+}
+
+func initKubeIntegration(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initUsers) == 0 {
+		initUser(tester, t)
+	}
+
+	ki := &ints.KubeIntegration{
+		Mechanism:  ints.KubeLocal,
+		ProjectID:  tester.initProjects[0].ID,
+		UserID:     tester.initUsers[0].ID,
+		Kubeconfig: []byte("current-context: testing\n"),
+	}
+
+	ki, err := tester.repo.KubeIntegration.CreateKubeIntegration(ki)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initKIs = append(tester.initKIs, ki)
+}
+
+func initOIDCIntegration(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initUsers) == 0 {
+		initUser(tester, t)
+	}
+
+	oidc := &ints.OIDCIntegration{
+		Client:       ints.OIDCKube,
+		ProjectID:    tester.initProjects[0].ID,
+		UserID:       tester.initUsers[0].ID,
+		IssuerURL:    []byte("https://oidc.example.com"),
+		ClientID:     []byte("exampleclientid"),
+		ClientSecret: []byte("exampleclientsecret"),
+		IDToken:      []byte("idtoken"),
+		RefreshToken: []byte("refreshtoken"),
+	}
+
+	oidc, err := tester.repo.OIDCIntegration.CreateOIDCIntegration(oidc)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initOIDCs = append(tester.initOIDCs, oidc)
+}
+
+func initOAuthIntegration(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initUsers) == 0 {
+		initUser(tester, t)
+	}
+
+	oauth := &ints.OAuthIntegration{
+		Client:       ints.OAuthGithub,
+		ProjectID:    tester.initProjects[0].ID,
+		UserID:       tester.initUsers[0].ID,
+		ClientID:     []byte("exampleclientid"),
+		AccessToken:  []byte("idtoken"),
+		RefreshToken: []byte("refreshtoken"),
+	}
+
+	oauth, err := tester.repo.OAuthIntegration.CreateOAuthIntegration(oauth)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initOAuths = append(tester.initOAuths, oauth)
+}
+
+func initGCPIntegration(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initUsers) == 0 {
+		initUser(tester, t)
+	}
+
+	gcp := &ints.GCPIntegration{
+		ProjectID:    tester.initProjects[0].ID,
+		UserID:       tester.initUsers[0].ID,
+		GCPProjectID: "test-proj-123456",
+		GCPUserEmail: "test@test.it",
+		GCPKeyData:   []byte("{\"test\":\"key\"}"),
+	}
+
+	gcp, err := tester.repo.GCPIntegration.CreateGCPIntegration(gcp)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initGCPs = append(tester.initGCPs, gcp)
+}
+
+func initAWSIntegration(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initUsers) == 0 {
+		initUser(tester, t)
+	}
+
+	aws := &ints.AWSIntegration{
+		ProjectID:          tester.initProjects[0].ID,
+		UserID:             tester.initUsers[0].ID,
+		AWSEntityID:        "entity",
+		AWSCallerID:        "caller",
+		AWSClusterID:       []byte("example-cluster-0"),
+		AWSAccessKeyID:     []byte("accesskey"),
+		AWSSecretAccessKey: []byte("secret"),
+		AWSSessionToken:    []byte("optional"),
+	}
+
+	aws, err := tester.repo.AWSIntegration.CreateAWSIntegration(aws)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initAWSs = append(tester.initAWSs, aws)
+}
+
+func initClusterCandidate(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	cc := &models.ClusterCandidate{
+		AuthMechanism:     models.AWS,
+		ProjectID:         tester.initProjects[0].ID,
+		CreatedClusterID:  0,
+		Resolvers:         []models.ClusterResolver{},
+		Name:              "cluster-test",
+		Server:            "https://localhost",
+		ContextName:       "context-test",
+		AWSClusterIDGuess: []byte("example-cluster-0"),
+		Kubeconfig:        []byte("current-context: testing\n"),
+	}
+
+	cc, err := tester.repo.Cluster.CreateClusterCandidate(cc)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initCCs = append(tester.initCCs, cc)
+}
+
+func initCluster(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initKIs) == 0 {
+		initKubeIntegration(tester, t)
+	}
+
+	cluster := &models.Cluster{
+		ProjectID:                tester.initProjects[0].ID,
+		Name:                     "cluster-test",
+		Server:                   "https://localhost",
+		KubeIntegrationID:        tester.initKIs[0].ID,
+		CertificateAuthorityData: []byte("-----BEGIN"),
+	}
+
+	cluster, err := tester.repo.Cluster.CreateCluster(cluster)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initClusters = append(tester.initClusters, cluster)
+}
+
+func initGitRepo(tester *tester, t *testing.T) {
+	t.Helper()
+
+	if len(tester.initProjects) == 0 {
+		initProject(tester, t)
+	}
+
+	if len(tester.initOAuths) == 0 {
+		initOAuthIntegration(tester, t)
+	}
+
+	gr := &models.GitRepo{
+		ProjectID:          tester.initProjects[0].ID,
+		RepoEntity:         "porter-dev",
+		OAuthIntegrationID: tester.initOAuths[0].ID,
+	}
+
+	gr, err := tester.repo.GitRepo.CreateGitRepo(gr)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initGRs = append(tester.initGRs, gr)
+}

+ 23 - 0
internal/repository/gorm/cluster.go

@@ -47,6 +47,13 @@ func (repo *ClusterRepository) CreateClusterCandidate(
 		return nil, err
 	}
 
+	// decrypt at the end to return
+	err = repo.DecryptClusterCandidateData(cc, repo.key)
+
+	if err != nil {
+		return nil, err
+	}
+
 	return cc, nil
 }
 
@@ -143,6 +150,12 @@ func (repo *ClusterRepository) CreateCluster(
 		return nil, err
 	}
 
+	err = repo.DecryptClusterData(cluster, repo.key)
+
+	if err != nil {
+		return nil, err
+	}
+
 	return cluster, nil
 }
 
@@ -226,6 +239,16 @@ func (repo *ClusterRepository) EncryptClusterData(
 		cluster.CertificateAuthorityData = cipherData
 	}
 
+	if tok := cluster.TokenCache.Token; len(tok) > 0 {
+		cipherData, err := repository.Encrypt(tok, key)
+
+		if err != nil {
+			return err
+		}
+
+		cluster.TokenCache.Token = cipherData
+	}
+
 	return nil
 }