Files
threshold/internal/server/testing.go
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

258 lines
8.5 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2022-06-20 18:20:17 -07:00
package server
2022-05-10 10:03:08 -04:00
import (
"context"
"crypto/rand"
mathRand "math/rand"
"strings"
2022-05-10 10:03:08 -04:00
"testing"
"time"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/timestamp"
"github.com/hashicorp/boundary/internal/errors"
2022-05-10 10:03:08 -04:00
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
2022-06-20 18:20:17 -07:00
"github.com/hashicorp/boundary/internal/server/store"
"github.com/hashicorp/boundary/internal/types/scope"
2022-09-08 13:19:21 -04:00
"github.com/hashicorp/boundary/version"
2022-05-10 10:03:08 -04:00
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/registration"
"github.com/hashicorp/nodeenrollment/rotation"
"github.com/hashicorp/nodeenrollment/storage/file"
"github.com/hashicorp/nodeenrollment/types"
2022-05-10 10:03:08 -04:00
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
)
const defaultLength = 20
// Generate random bytes for byte fields
func populateBytes(length int) []byte {
fieldBytes := make([]byte, length)
2024-02-16 08:30:16 -05:00
if _, err := rand.Read(fieldBytes); err != nil {
panic(err)
}
2022-05-10 10:03:08 -04:00
return fieldBytes
}
2022-11-16 17:17:28 -06:00
func TestKmsKey(ctx context.Context, t *testing.T, conn *db.DB, wrapper wrapping.Wrapper) (string, wrapping.Wrapper) {
2022-05-10 10:03:08 -04:00
t.Helper()
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
kmsCache := kms.TestKms(t, conn, wrapper)
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
testKey, err := databaseWrapper.KeyId(ctx)
require.NoError(t, err)
2022-11-16 17:17:28 -06:00
return testKey, databaseWrapper
2022-05-10 10:03:08 -04:00
}
2022-05-20 11:55:54 -07:00
func TestRootCertificate(ctx context.Context, t *testing.T, conn *db.DB, kmsKey string) *RootCertificate {
2022-05-10 10:03:08 -04:00
t.Helper()
rw := db.New(conn)
beforeTimestamp := &timestamp.Timestamp{Timestamp: timestamppb.New(time.Now().Add(-1 * time.Hour))}
afterTimestamp := &timestamp.Timestamp{Timestamp: timestamppb.New(time.Now().Add(1 * time.Hour))}
rootCertKeys := RootCertificateKeys{
publicKey: populateBytes(defaultLength),
privateKey: populateBytes(defaultLength),
}
cert, err := newRootCertificate(ctx, mathRand.Uint64(), populateBytes(defaultLength), beforeTimestamp, afterTimestamp,
2022-05-10 10:03:08 -04:00
rootCertKeys, kmsKey, CurrentState)
require.NoError(t, err)
2022-05-10 10:03:08 -04:00
err = rw.Create(ctx, cert)
require.NoError(t, err)
2022-05-20 11:55:54 -07:00
return cert
2022-05-10 10:03:08 -04:00
}
2022-11-16 17:17:28 -06:00
func TestWorkerAuth(t *testing.T, conn *db.DB, worker *Worker, kmsWrapper wrapping.Wrapper) *WorkerAuth {
2022-05-10 10:03:08 -04:00
t.Helper()
2022-06-15 10:47:25 -07:00
ctx := context.Background()
2022-05-10 10:03:08 -04:00
rw := db.New(conn)
wSignPubKey := populateBytes(defaultLength)
wEncPubKey := populateBytes(defaultLength)
workerKeys := WorkerKeys{workerSigningPubKey: wSignPubKey, workerEncryptionPubKey: wEncPubKey}
controllerKey := populateBytes(defaultLength)
nonce := populateBytes(defaultLength)
opt := []Option{
WithWorkerKeys(workerKeys),
WithControllerEncryptionPrivateKey(controllerKey),
WithNonce(nonce),
}
workerAuth, err := newWorkerAuth(ctx, "worker-key-identifier", worker.PublicId, opt...)
require.NoError(t, err)
2022-11-16 17:17:28 -06:00
require.NoError(t, workerAuth.encrypt(ctx, kmsWrapper))
require.NoError(t, rw.Create(ctx, workerAuth))
2022-05-10 10:03:08 -04:00
2022-05-20 11:55:54 -07:00
return workerAuth
2022-05-10 10:03:08 -04:00
}
// TestKmsWorker inserts a worker into the db to satisfy foreign key constraints.
// The worker provided fields are auto generated. if WithName is not present a
// random name will be generated and assigned to the worker.
func TestKmsWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...Option) *Worker {
2022-05-10 10:03:08 -04:00
t.Helper()
ctx := context.Background()
2022-05-10 10:03:08 -04:00
rw := db.New(conn)
kms := kms.TestKms(t, conn, wrapper)
serversRepo, err := NewRepository(ctx, rw, rw, kms)
2022-05-10 10:03:08 -04:00
require.NoError(t, err)
2022-09-02 14:32:41 -04:00
opts := GetOpts(opt...)
2022-05-10 10:03:08 -04:00
if opts.withName == "" {
namePart, err := newWorkerId(ctx)
require.NoError(t, err)
name := "test-worker-" + strings.ToLower(namePart)
opt = append(opt, WithName(name))
}
if opts.withAddress == "" {
address := "127.0.0.1"
opt = append(opt, WithAddress(address))
}
if opts.withReleaseVersion == "" {
// Only set the release version if it isn't already set
versionInfo := version.Get()
relVer := versionInfo.FullVersionNumber(false)
opt = append(opt, WithReleaseVersion(relVer))
}
wrk := NewWorker(scope.Global.String(), opt...)
2025-01-08 15:18:03 +00:00
wrk, err = TestUpsertAndReturnWorker(ctx, t, wrk, serversRepo)
require.NoError(t, err)
2022-05-10 10:03:08 -04:00
require.NoError(t, err)
require.NotNil(t, wrk)
require.Equal(t, "kms", wrk.Type)
2022-06-03 11:19:04 -07:00
if len(opts.withWorkerTags) > 0 {
2025-01-08 15:18:03 +00:00
var tags []*store.ConfigTag
for _, t := range opts.withWorkerTags {
2025-01-08 15:18:03 +00:00
tags = append(tags, &store.ConfigTag{
WorkerId: wrk.GetPublicId(),
Key: t.Key,
Value: t.Value,
})
}
require.NoError(t, rw.CreateItems(ctx, tags))
}
2022-06-15 10:47:25 -07:00
wrk, err = serversRepo.LookupWorker(ctx, wrk.GetPublicId())
require.NoError(t, err)
2022-05-24 15:08:02 -07:00
return wrk
2022-05-10 10:03:08 -04:00
}
2022-06-15 10:47:25 -07:00
// TestPkiWorker inserts a worker into the db to satisfy foreign key constraints.
// The worker provided fields are auto generated. WithName and WithDescription,
// are applied to the resource name, description if present. WithTestPkiWorkerAuthorizedKeyId
// can be used to make the PkiWorker authorized in which case the string pointer
// passed to WithTestPkiWorkerAuthorizedKeyId is set to the key id.
func TestPkiWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...Option) *Worker {
t.Helper()
ctx := context.Background()
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
serversRepo, err := NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
2022-09-02 14:32:41 -04:00
opts := GetOpts(opt...)
require.NoError(t, err)
wrk := NewWorker(scope.Global.String(),
opt...)
wrk, err = serversRepo.CreateWorker(ctx, wrk, opt...)
require.NoError(t, err)
require.NotNil(t, wrk)
if len(opts.withWorkerTags) > 0 {
switch opts.withTestUseInputTagsAsApiTags {
case true:
var tags []*store.ApiTag
for _, t := range opts.withWorkerTags {
tags = append(tags, &store.ApiTag{
WorkerId: wrk.GetPublicId(),
Key: t.Key,
Value: t.Value,
})
}
require.NoError(t, rw.CreateItems(ctx, tags))
default:
var tags []*store.ConfigTag
for _, t := range opts.withWorkerTags {
tags = append(tags, &store.ConfigTag{
WorkerId: wrk.GetPublicId(),
Key: t.Key,
Value: t.Value,
})
}
require.NoError(t, rw.CreateItems(ctx, tags))
}
}
if opts.withTestPkiWorkerAuthorized {
err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
// We always try to create root global scope keys, but if it already exists, just continue...
require.True(t, err == nil || errors.IsUniqueError(err), err)
rootStorage, err := NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(t, err)
_, err = rotation.RotateRootCertificates(ctx, rootStorage)
require.NoError(t, err)
// Create struct to pass in with workerId that will be passed along to storage
state, err := AttachWorkerIdToState(ctx, wrk.PublicId)
require.NoError(t, err)
// This happens on the worker
fileStorage, err := file.New(ctx)
require.NoError(t, err)
nodeCreds, err := types.NewNodeCredentials(ctx, fileStorage)
require.NoError(t, err)
// Create request using worker id
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(ctx)
require.NoError(t, err)
registeredNode, err := registration.AuthorizeNode(ctx, rootStorage, fetchReq, nodeenrollment.WithState(state))
require.NoError(t, err)
if opts.withTestPkiWorkerKeyId != nil {
*opts.withTestPkiWorkerKeyId = registeredNode.Id
}
}
2022-06-15 10:47:25 -07:00
wrk, err = serversRepo.LookupWorker(ctx, wrk.GetPublicId())
require.NoError(t, err)
return wrk
}
2025-01-08 15:18:03 +00:00
// TestLookupWorkerByName looks up a worker by name
func TestLookupWorkerByName(ctx context.Context, t *testing.T, name string, serversRepo *Repository) (*Worker, error) {
workers, err := serversRepo.ListWorkers(ctx, []string{"global"})
require.NoError(t, err)
for _, w := range workers {
if w.GetName() == name {
return w, nil
}
}
return nil, nil
}
// TestUpsertAndReturnWorker upserts and returns a worker
func TestUpsertAndReturnWorker(ctx context.Context, t *testing.T, w *Worker, serversRepo *Repository, opt ...Option) (*Worker, error) {
workerId, err := serversRepo.UpsertWorkerStatus(ctx, w, opt...)
require.NoError(t, err)
require.NotEmpty(t, workerId)
return serversRepo.LookupWorker(ctx, workerId)
}
// TestUseCommunityFilterWorkersFn is used to ensure that CE tests run from the
// ENT repo use the CE worker filtering logic. WARNING: Do NOT run tests in
// parallel when using this.
func TestUseCommunityFilterWorkersFn(t *testing.T) {
oldFn := FilterWorkersFn
FilterWorkersFn = filterWorkers
t.Cleanup(func() {
FilterWorkersFn = oldFn
})
}