...

Source file src/edge-infra.dev/pkg/edge/edge-issuer/controllers/signer_test.go

Documentation: edge-infra.dev/pkg/edge/edge-issuer/controllers

     1  package controllers
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
    12  	cmMeta "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  	"google.golang.org/api/option"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  
    18  	"edge-infra.dev/pkg/edge/api/sql/plugin"
    19  	"edge-infra.dev/pkg/edge/api/sql/utils"
    20  
    21  	edgeissuerapi "edge-infra.dev/pkg/edge/edge-issuer/api/v1alpha1"
    22  	"edge-infra.dev/test/f2"
    23  	"edge-infra.dev/test/f2/x/postgres"
    24  )
    25  
    26  const (
    27  	TestTenantID     = "3396a52c-6a22-4049-9593-5a63b596a377"
    28  	TestBannerID     = "3396a52c-6a22-4049-9593-5a63b596a101"
    29  	TestCAPoolEdgeID = "3396a52c-6a22-4049-9593-5a63b596a379"
    30  	TestCACertEdgeID = "3396a52c-6a22-4049-9593-5a63b596a380"
    31  	SelectBannerID   = `SELECT banner_edge_id FROM banners;`
    32  	SelectCAPoolID   = `SELECT ca_pool_edge_id FROM ca_pools;`
    33  	SelectCACert     = `SELECT ca_cert_edge_id FROM ca_certificates;`
    34  
    35  	caCert = `
    36  	-----BEGIN CERTIFICATE-----
    37  	MIIBiTCCAS+gAwIBAgIUUzqzORE0Axa4SXpblqd7fPDdQlUwCgYIKoZIzj0EAwIw
    38  	GjEYMBYGA1UEAwwPRWRnZUlzc3VlclBLSUNBMB4XDTI1MDIxNzE0NTEwM1oXDTM1
    39  	MDIxNTE0NTEwM1owGjEYMBYGA1UEAwwPRWRnZUlzc3VlclBLSUNBMFkwEwYHKoZI
    40  	zj0CAQYIKoZIzj0DAQcDQgAE27Uu6BoAwmZwzKtpY4KKIus3g16lHZeZPnmHx3Jj
    41  	9uAraOr16GMdysirSCbt/6A/Q7EecIB8V3iEoAThER/1uqNTMFEwHQYDVR0OBBYE
    42  	FPoGyYTcuzT6XYcrY5iskdk7whgGMB8GA1UdIwQYMBaAFPoGyYTcuzT6XYcrY5is
    43  	kdk7whgGMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgE3/PuD3H
    44  	5o10t6pMI1tflzgyYOYuZubnKNtFv79uZCoCIQCpQCbwC+nLRHO4hkSTCiIx/8h2
    45  	yQethOhg/kQ2y2xyWA==
    46  	-----END CERTIFICATE-----`
    47  
    48  	//nolint: gosec
    49  	testKey = `-----BEGIN EC PRIVATE KEY-----
    50  	MHcCAQEEIOHQktpCBGoAI5lhPNpyzLUqfNf1hFieabgD4W+UrwPQoAoGCCqGSM49
    51  	AwEHoUQDQgAE27Uu6BoAwmZwzKtpY4KKIus3g16lHZeZPnmHx3Jj9uAraOr16GMd
    52  	ysirSCbt/6A/Q7EecIB8V3iEoAThER/1ug==
    53  	-----END EC PRIVATE KEY-----`
    54  )
    55  
    56  var TestTime = time.Now().Format(time.RFC3339)
    57  
    58  // Seed data for the tests
    59  var Seed = []plugin.Seed{
    60  	{
    61  		Name:     "seed-tenants.tmpl",
    62  		Priority: 0,
    63  		Data: utils.Tenants{
    64  			{
    65  				EdgeID:      TestTenantID,
    66  				BSLID:       "e65ac3c1-f46c-4b61-88cd-d6241e3a919d",
    67  				Description: "test description",
    68  				Name:        "testOrganization",
    69  			},
    70  		},
    71  	},
    72  	{
    73  		Name:     "seed-banners.tmpl",
    74  		Priority: 1,
    75  		Data: utils.Banners{
    76  			{
    77  				EdgeID:               TestBannerID,
    78  				BannerType:           "org",
    79  				ProjectID:            "d56bf564-90f7-4036-9eab-9efd435e68fe",
    80  				TenantID:             TestTenantID,
    81  				BSLID:                "bc1d5e11-6b1b-405b-a9c5-fec50090c31b",
    82  				Description:          "test description",
    83  				Name:                 "testBanner1",
    84  				MismatchInfo:         nil,
    85  				InfraStatus:          "PROVISIONING",
    86  				InfraStatusUpdatedAt: time.Now().Format(time.RFC3339),
    87  				BslEntityTypes:       "{}",
    88  			},
    89  		},
    90  	},
    91  	{
    92  		Name:     "seed-pools.tmpl",
    93  		Priority: 2,
    94  		Data: utils.CAPools{
    95  			{
    96  				BannerEdgeID: TestBannerID,
    97  				CAPoolEdgeID: TestCAPoolEdgeID,
    98  			},
    99  		},
   100  	},
   101  	{
   102  		Name:     "seed-certificates.tmpl",
   103  		Priority: 3,
   104  		Data: utils.CACertificates{
   105  			{
   106  				CACertEdgeID:  TestCACertEdgeID,
   107  				CAPoolEdgeID:  TestCAPoolEdgeID,
   108  				Status:        "active",
   109  				CertRef:       "test-cert-ref-1",
   110  				PrivateKeyRef: "test-private-key-ref-1",
   111  				Expiration:    time.Now().Add(1 * time.Hour).Format("2006-01-02 15:04:05"),
   112  			},
   113  		},
   114  	},
   115  }
   116  
   117  var f f2.Framework
   118  
   119  func TestMain(m *testing.M) {
   120  	// Set up test framework in TestMain
   121  	f = f2.New(context.Background(),
   122  		f2.WithExtensions(
   123  			postgres.New(postgres.ApplySeedModel()),
   124  		),
   125  	)
   126  	os.Exit(f.Run(m))
   127  }
   128  func TestSeedValid(t *testing.T) {
   129  	feat := f2.NewFeature("Test add seed data works").
   130  		Setup("Add Seed data", postgres.WithData(Seed)).
   131  		Test("Test Data exists", func(ctx f2.Context, t *testing.T) f2.Context {
   132  			var require = require.New(t)
   133  			pg := postgres.FromContextT(ctx, t)
   134  			db := pg.DB()
   135  
   136  			// check ca pools contains the correct data
   137  			rows, err := db.QueryContext(ctx, SelectCAPoolID)
   138  			require.NoError(err, "Failed to query database.")
   139  
   140  			var caPoolEdgeID string
   141  			results := []string{}
   142  			for rows.Next() {
   143  				err = rows.Scan(&caPoolEdgeID)
   144  				require.NoError(err)
   145  				results = append(results, caPoolEdgeID)
   146  			}
   147  
   148  			// check the data contains a single ca pool and it matches the constant in data.
   149  			require.Len(results, 1, "Wrong number of results returned from database query, Expected: %v, Actual %v", 1, len(results))
   150  			// require the result matches the constant in data
   151  			require.Equal(results[0], TestCAPoolEdgeID, "ca_pool_edge_id returned from database did not match expected value: %q", TestCAPoolEdgeID)
   152  
   153  			// test ca certificates contains the correct data
   154  			rows, err = db.QueryContext(ctx, SelectCACert)
   155  			require.NoError(err, "Failed to query database.")
   156  
   157  			var caCertEdgeID string
   158  			results = []string{}
   159  			for rows.Next() {
   160  				err = rows.Scan(&caCertEdgeID)
   161  				require.NoError(err)
   162  				results = append(results, caCertEdgeID)
   163  			}
   164  
   165  			// check the data contains a single ca cert and it matches the constant in data.
   166  			require.Len(results, 1, "Wrong number of results returned from database query, Expected: %v, Actual %v", 1, len(results))
   167  			// require the result matches the constant in data
   168  			require.Equal(results[0], TestCACertEdgeID, "ca_cert_edge_id returned from database did not match expected value: %q", TestCACertEdgeID)
   169  
   170  			return ctx
   171  		}).Feature()
   172  	f.Test(t, feat)
   173  }
   174  
   175  func TestEdgeIssuer(t *testing.T) {
   176  	feat := f2.NewFeature("Test Edge Issuer").
   177  		Setup("Load Data", postgres.WithData(Seed)).
   178  		Setup("Add EdgeIssuer Data", func(ctx f2.Context, t *testing.T) f2.Context {
   179  			var require = require.New(t)
   180  			pg := postgres.FromContextT(ctx, t)
   181  			db := pg.DB()
   182  
   183  			sMgr := &mockSecretManager{clients: make(map[string]*mockSecretManagerClient)}
   184  			c, err := sMgr.NewWithOptions(ctx, TestTenantID)
   185  			require.NoError(err, "Failed to create secret manager client.")
   186  
   187  			caCertBase64 := base64.StdEncoding.EncodeToString([]byte(caCert))
   188  			caPrivKeyBase64 := base64.StdEncoding.EncodeToString([]byte(testKey))
   189  
   190  			err = c.AddSecret(ctx, "test-cert-ref", []byte(caCertBase64), nil, false, nil, "1")
   191  			require.NoError(err, "Failed to add ca cert secret to secret manager.")
   192  
   193  			err = c.AddSecret(ctx, "test-private-key-ref", []byte(caPrivKeyBase64), nil, false, nil, "1")
   194  			require.NoError(err, "Failed to add private key secret to secret manager.")
   195  
   196  			// now for actual testing that issuer is working
   197  			issuer := &Issuer{
   198  				Config: &Config{
   199  					DB:                db,
   200  					TopLevelProjectID: TestTenantID,
   201  					BannerID:          TestBannerID,
   202  				},
   203  				SecretManager: sMgr,
   204  			}
   205  
   206  			issuerObj := &edgeissuerapi.EdgeIssuer{}
   207  			err = issuer.Check(ctx, issuerObj)
   208  			require.NoError(err, "Failed to check issuer.")
   209  
   210  			// confirm issuer certs match that in database
   211  			require.Equal(string(issuer.CACert), caCert, "CA cert in issuer does not match that in database.")
   212  			require.Equal(string(issuer.CAPrivateKey), testKey, "CA key in issuer does not match that in database.")
   213  
   214  			return ctx
   215  		}).Feature()
   216  
   217  	f.Test(t, feat)
   218  }
   219  
   220  type MockSigner struct {
   221  	mock.Mock
   222  }
   223  
   224  type mockSecret struct {
   225  	value []byte
   226  }
   227  
   228  type mockSecretManager struct {
   229  	clients map[string]*mockSecretManagerClient
   230  }
   231  
   232  func (m *MockSigner) GetCreationTimestamp() metav1.Time {
   233  	return metav1.Now()
   234  }
   235  
   236  func (m *MockSigner) GetConditions() []cmMeta.CertificateRequestCondition {
   237  	return []cmMeta.CertificateRequestCondition{}
   238  }
   239  
   240  func (m *MockSigner) GetAnnotations() map[string]string {
   241  	return map[string]string{}
   242  }
   243  
   244  func (sm *mockSecretManager) NewWithOptions(_ context.Context, projectID string, _ ...option.ClientOption) (secretManagerClient, error) {
   245  	if sm.clients[projectID] == nil {
   246  		sm.clients[projectID] = &mockSecretManagerClient{
   247  			secrets: make(map[string]*mockSecret),
   248  		}
   249  	}
   250  	return sm.clients[projectID], nil
   251  }
   252  
   253  func (smc *mockSecretManagerClient) GetSecret(_ context.Context, secretID string) (*secretmanagerpb.Secret, error) {
   254  	s := smc.secrets[secretID]
   255  	if s == nil {
   256  		return nil, fmt.Errorf("secret %s not found", secretID)
   257  	}
   258  	spb := &secretmanagerpb.Secret{
   259  		Name: secretID,
   260  	}
   261  	return spb, nil
   262  }
   263  
   264  func (smc *mockSecretManagerClient) AddSecret(_ context.Context, secretID string, secret []byte, _ map[string]string, _ bool, _ *time.Time, _ string) error {
   265  	smc.secrets[secretID] = &mockSecret{value: secret}
   266  	return nil
   267  }
   268  
   269  type mockSecretManagerClient struct {
   270  	secrets map[string]*mockSecret
   271  }
   272  
   273  func (smc *mockSecretManagerClient) GetSecretVersionValue(_ context.Context, secretID string, _ string) ([]byte, error) {
   274  	s := smc.secrets[secretID]
   275  	if s == nil {
   276  		return nil, fmt.Errorf("secret %s not found", secretID)
   277  	}
   278  	return s.value, nil
   279  }
   280  
   281  func (smc *mockSecretManagerClient) GetLatestSecretValue(_ context.Context, secretID string) ([]byte, error) {
   282  	s := smc.secrets[secretID]
   283  	if s == nil {
   284  		return nil, fmt.Errorf("secret %s not found", secretID)
   285  	}
   286  	return s.value, nil
   287  }
   288  

View as plain text