fix (kms): move oplog DEK into its own internal kms (#3665)

* fix (auth/ldap): fix which DEK is used for oplog during authenticate

* chore: update go-kms-wrapping dep for new extras/kms changes

The latest version supports setting a table name prefix for a kms
which is needed to fix our oplog DEK problem

* chore: update extras/kms dep

This latest version supports an optional TableNamePrefix which is
required to fix our existing oplog DEK issue.

* fix (oplog): schema oplog DEK fix

These changes will allow use to store the oplog DEK in it's own
set of tables, so they won't get deleted when a scope is deleted

* fix (kms): move oplog DEK into its own internal kms

* tests: update tests to be compatible with oplog fix

* tests: remove migration tests which are incompatible with oplog fix

These tests no longer work because they are missing the required
schema changes for the oplog fix
This commit is contained in:
Jim authored and GitHub committed 2023-09-06 18:25:49 -04:00
1 parent 9a6b0d26cb
commit a16033b73a
31 files changed
+733 -1943

No files matched your search

+25 -25
View File
@@ -13,7 +13,7 @@ require (
github.com/fatih/structs v1.1.0
github.com/favadi/protoc-go-inject-tag v1.4.0
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang-migrate/migrate/v4 v4.15.1
github.com/golang-migrate/migrate/v4 v4.16.2
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.5.9
@@ -28,7 +28,7 @@ require (
github.com/hashicorp/go-bexpr v0.1.12
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-hclog v1.5.0
github.com/hashicorp/go-kms-wrapping/v2 v2.0.10-0.20230601143830-08d524b564ba
github.com/hashicorp/go-kms-wrapping/v2 v2.0.12
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.2
github.com/hashicorp/go-rootcerts v1.0.2
@@ -48,7 +48,7 @@ require (
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/vault/api v1.9.1
github.com/iancoleman/strcase v0.2.0
github.com/jackc/pgconn v1.14.0
github.com/jackc/pgconn v1.14.1
github.com/jackc/pgx/v4 v4.18.1 // indirect
github.com/jefferai/keyring v1.1.7-0.20220316160357-58a74bb55891
github.com/kr/pretty v0.3.1
@@ -69,34 +69,34 @@ require (
github.com/ryanuber/go-glob v1.0.0
github.com/stretchr/testify v1.8.4
github.com/zalando/go-keyring v0.2.3
go.uber.org/atomic v1.9.0
golang.org/x/crypto v0.11.0
golang.org/x/sync v0.1.0
golang.org/x/sys v0.10.0
golang.org/x/term v0.10.0
golang.org/x/tools v0.6.0
go.uber.org/atomic v1.11.0
golang.org/x/crypto v0.12.0
golang.org/x/sync v0.2.0
golang.org/x/sys v0.12.0
golang.org/x/term v0.11.0
golang.org/x/tools v0.9.1
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e
google.golang.org/grpc v1.55.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
google.golang.org/protobuf v1.31.0
gorm.io/driver/postgres v1.5.2
gorm.io/gorm v1.25.1 // indirect
mvdan.cc/gofumpt v0.3.1
gorm.io/gorm v1.25.4 // indirect
mvdan.cc/gofumpt v0.4.0
nhooyr.io/websocket v1.8.7
)
require github.com/hashicorp/go-dbw v0.0.0-20230605211904-d40e5c9d5995
require github.com/hashicorp/go-dbw v0.1.0
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/cenkalti/backoff/v4 v4.2.0
github.com/creack/pty v1.1.18
github.com/hashicorp/cap/ldap v0.0.0-20230824195246-512b26a36f79
github.com/hashicorp/dbassert v0.0.0-20230405175854-2d88acd5134b
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20221122211539-47c893099f13
github.com/hashicorp/dbassert v0.0.0-20230622135851-cc4c0f18f4a7
github.com/hashicorp/go-kms-wrapping/extras/kms/v2 v2.0.0-20230902160534-7a966e6313fd
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/nodeenrollment v0.2.6
github.com/jackc/pgx/v5 v5.3.1
github.com/jackc/pgx/v5 v5.4.3
github.com/jimlambrt/gldap v0.1.7
github.com/kelseyhightower/envconfig v1.4.0
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
@@ -114,7 +114,7 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/alessio/shellescape v1.4.1 // indirect
github.com/apex/log v1.9.0 // indirect
@@ -162,8 +162,8 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
@@ -171,7 +171,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -186,21 +186,21 @@ require (
github.com/sethvargo/go-diceware v0.3.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/sirupsen/logrus v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/urfave/cli/v2 v2.3.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xo/dburl v0.14.2 // indirect
go.uber.org/goleak v1.1.10 // indirect
golang.org/x/mod v0.8.0 // indirect
github.com/xo/dburl v0.16.0 // indirect
go.uber.org/goleak v1.1.12 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/sqlite v1.5.1 // indirect
gorm.io/driver/sqlite v1.5.3 // indirect
)
+54 -898
View File
File diff suppressed because it is too large. Load diff
@@ -119,7 +119,7 @@ func (r *Repository) Authenticate(ctx context.Context, authMethodId, loginName,
acct.MemberOfGroups = string(encodedGroups)
}
databaseWrapper, err := r.kms.GetWrapper(ctx, am.ScopeId, kms.KeyPurposeDatabase)
oplogWrapper, err := r.kms.GetWrapper(ctx, am.ScopeId, kms.KeyPurposeOplog)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
@@ -136,7 +136,7 @@ func (r *Repository) Authenticate(ctx context.Context, authMethodId, loginName,
Target: db.Columns{"public_id"}, // id is predictable and uses both auth method id and login name for inputs
Action: db.SetColumns([]string{"full_name", "email", "dn", "member_of_groups"}),
}),
db.WithOplog(databaseWrapper, md),
db.WithOplog(oplogWrapper, md),
); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to create/update ldap account"))
}
+3
View File
@@ -27,6 +27,9 @@ func TestRewrap_authMethodRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -27,6 +27,9 @@ func TestRewrap_argon2ConfigRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
+3
View File
@@ -26,6 +26,9 @@ func TestRewrap_authTokenRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -28,6 +28,9 @@ func TestRewrap_credStaticUsernamePasswordRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -89,6 +92,9 @@ func TestRewrap_credStaticSshPrivKeyRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -194,6 +200,9 @@ func TestRewrap_credStaticJsonRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -26,6 +26,9 @@ func TestRewrap_credVaultClientCertificateRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -87,6 +90,9 @@ func TestRewrap_credVaultTokenRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
+3 -3
View File
@@ -20,7 +20,7 @@ import (
func TestDb_Create_OnConflict(t *testing.T) {
ctx := context.Background()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestDBWrapper(t, conn, "oplog")
oplogWrapper := db.TestOplogWrapper(t, conn)
rw := db.New(conn)
db.TestCreateTables(t, conn)
@@ -172,7 +172,7 @@ func TestDb_Create_OnConflict(t *testing.T) {
"op-type": []string{oplog.OpType_OP_TYPE_CREATE.String()},
}
var rowsAffected int64
opts := []db.Option{db.WithOnConflict(&tt.onConflict), db.WithOplog(wrapper, md), db.WithReturnRowsAffected(&rowsAffected)}
opts := []db.Option{db.WithOnConflict(&tt.onConflict), db.WithOplog(oplogWrapper, md), db.WithReturnRowsAffected(&rowsAffected)}
if tt.additionalOpts != nil {
opts = append(opts, tt.additionalOpts...)
}
@@ -222,7 +222,7 @@ func TestDb_Create_OnConflict(t *testing.T) {
users := []any{}
users = append(users, conflictUser)
var rowsAffected int64
err = rw.CreateItems(ctx, users, db.WithOnConflict(&onConflict), db.WithOplog(wrapper, md), db.WithReturnRowsAffected(&rowsAffected))
err = rw.CreateItems(ctx, users, db.WithOnConflict(&onConflict), db.WithOplog(oplogWrapper, md), db.WithReturnRowsAffected(&rowsAffected))
require.NoError(err)
foundUser, err := db_test.NewTestUser()
require.NoError(err)
+34 -34
View File
@@ -62,7 +62,7 @@ func TestDb_Update(t *testing.T) {
publicId, err := NewPublicId(testCtx, "testuser")
require.NoError(t, err)
id := testId(t)
wrapper := TestDBWrapper(t, conn, "oplog")
oplogWrapper := TestOplogWrapper(t, conn)
badVersion := uint32(22)
versionOne := uint32(1)
@@ -403,7 +403,7 @@ func TestDb_Update(t *testing.T) {
rowsUpdated, err := w.Update(testCtx, user, []string{"Name"}, nil,
// write oplogs for this update
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"key-only": nil,
"deployment": []string{"amex"},
@@ -450,7 +450,7 @@ func TestDb_Update(t *testing.T) {
user,
[]string{"Name"}, nil,
NewOplogMsg(&updateMsg),
WithOplog(wrapper, oplog.Metadata{"alice": []string{"bob"}}),
WithOplog(oplogWrapper, oplog.Metadata{"alice": []string{"bob"}}),
)
require.Error(err)
assert.Equal(0, rowsUpdated)
@@ -493,7 +493,7 @@ func TestDb_Update(t *testing.T) {
"resource-public-id": []string{user.PublicId},
// "op-type": []string{oplog.OpType_OP_TYPE_UPDATE.String()},
}
err = w.WriteOplogEntryWith(context.Background(), wrapper, ticket, metadata, []*oplog.Message{&createMsg, &updateMsg})
err = w.WriteOplogEntryWith(context.Background(), oplogWrapper, ticket, metadata, []*oplog.Message{&createMsg, &updateMsg})
require.NoError(err)
err = TestVerifyOplog(t, w, user.PublicId, WithOperation(oplog.OpType_OP_TYPE_UNSPECIFIED), WithCreateNotBefore(10*time.Second))
@@ -573,7 +573,7 @@ func TestDb_Update(t *testing.T) {
user.Name = "friendly-" + id
rowsUpdated, err := w.Update(context.Background(), user, []string{"Name"}, nil,
WithOplog(
wrapper,
oplogWrapper,
nil,
),
)
@@ -637,7 +637,7 @@ func TestDb_Create(t *testing.T) {
// intentionally not run with t.Parallel so we don't need to use DoTx for the Create tests
conn, _ := TestSetup(t, "postgres")
TestCreateTables(t, conn)
wrapper := TestDBWrapper(t, conn, "oplog")
oplogWrapper := TestOplogWrapper(t, conn)
t.Run("simple", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
w := New(conn)
@@ -675,7 +675,7 @@ func TestDb_Create(t *testing.T) {
context.Background(),
user,
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"key-only": nil,
"deployment": []string{"amex"},
@@ -706,7 +706,7 @@ func TestDb_Create(t *testing.T) {
context.Background(),
user,
NewOplogMsg(&createMsg),
WithOplog(wrapper, oplog.Metadata{"alice": []string{"bob"}}),
WithOplog(oplogWrapper, oplog.Metadata{"alice": []string{"bob"}}),
)
require.Error(err)
assert.True(errors.Match(errors.T(errors.InvalidParameter), err))
@@ -749,7 +749,7 @@ func TestDb_Create(t *testing.T) {
"resource-public-id": []string{user.PublicId},
}
err = w.WriteOplogEntryWith(context.Background(), wrapper, ticket, metadata, []*oplog.Message{&createMsg, &updateMsg})
err = w.WriteOplogEntryWith(context.Background(), oplogWrapper, ticket, metadata, []*oplog.Message{&createMsg, &updateMsg})
require.NoError(err)
err = TestVerifyOplog(t, w, user.PublicId, WithOperation(oplog.OpType_OP_TYPE_UNSPECIFIED), WithCreateNotBefore(10*time.Second))
@@ -790,7 +790,7 @@ func TestDb_Create(t *testing.T) {
context.Background(),
user,
WithOplog(
wrapper,
oplogWrapper,
nil,
),
)
@@ -1361,7 +1361,7 @@ func TestDb_DoTx(t *testing.T) {
func TestDb_Delete(t *testing.T) {
conn, _ := TestSetup(t, "postgres")
TestCreateTables(t, conn)
wrapper := TestDBWrapper(t, conn, "oplog")
oplogWrapper := TestOplogWrapper(t, conn)
newUser := func() *db_test.TestUser {
w := New(conn)
u, err := db_test.NewTestUser()
@@ -1409,7 +1409,7 @@ func TestDb_Delete(t *testing.T) {
{
name: "simple-no-oplog",
underlying: conn,
wrapper: wrapper,
wrapper: oplogWrapper,
args: args{
i: newUser(),
},
@@ -1419,7 +1419,7 @@ func TestDb_Delete(t *testing.T) {
{
name: "with-where-no-delete",
underlying: conn,
wrapper: wrapper,
wrapper: oplogWrapper,
args: args{
i: newUser(),
opt: []Option{WithWhere("1 = ?", 2)},
@@ -1431,7 +1431,7 @@ func TestDb_Delete(t *testing.T) {
{
name: "with-where-and-delete",
underlying: conn,
wrapper: wrapper,
wrapper: oplogWrapper,
args: args{
i: newUser(),
opt: []Option{WithWhere("1 = ?", 1)},
@@ -1442,7 +1442,7 @@ func TestDb_Delete(t *testing.T) {
{
name: "valid-with-oplog",
underlying: conn,
wrapper: wrapper,
wrapper: oplogWrapper,
args: args{
i: newUser(),
metadata: newMetadata,
@@ -1480,7 +1480,7 @@ func TestDb_Delete(t *testing.T) {
{
name: "nil-underlying",
underlying: nil,
wrapper: wrapper,
wrapper: oplogWrapper,
args: args{
i: newUser(),
},
@@ -1491,7 +1491,7 @@ func TestDb_Delete(t *testing.T) {
{
name: "not-found",
underlying: conn,
wrapper: wrapper,
wrapper: oplogWrapper,
args: args{
i: notFoundUser(),
},
@@ -1557,7 +1557,7 @@ func TestDb_Delete(t *testing.T) {
require.NoError(err)
deleteMsg := oplog.Message{}
rowsDeleted, err := w.Delete(context.Background(), user, NewOplogMsg(&deleteMsg), WithOplog(wrapper, oplog.Metadata{"alice": []string{"bob"}}))
rowsDeleted, err := w.Delete(context.Background(), user, NewOplogMsg(&deleteMsg), WithOplog(oplogWrapper, oplog.Metadata{"alice": []string{"bob"}}))
require.Error(err)
assert.Equal(0, rowsDeleted)
assert.True(errors.Match(errors.T(errors.InvalidParameter), err))
@@ -1598,7 +1598,7 @@ func TestDb_Delete(t *testing.T) {
metadata := oplog.Metadata{
"resource-public-id": []string{user.PublicId},
}
err = w.WriteOplogEntryWith(context.Background(), wrapper, ticket, metadata, []*oplog.Message{&createMsg, &deleteMsg})
err = w.WriteOplogEntryWith(context.Background(), oplogWrapper, ticket, metadata, []*oplog.Message{&createMsg, &deleteMsg})
require.NoError(err)
err = TestVerifyOplog(t, w, user.PublicId, WithOperation(oplog.OpType_OP_TYPE_UNSPECIFIED), WithCreateNotBefore(10*time.Second))
@@ -1678,7 +1678,7 @@ func TestDb_Query(t *testing.T) {
func TestDb_CreateItems(t *testing.T) {
db, _ := TestSetup(t, "postgres")
TestCreateTables(t, db)
wrapper := TestDBWrapper(t, db, "oplog")
oplogWrapper := TestOplogWrapper(t, db)
testOplogResourceId := testId(t)
createFn := func() []any {
@@ -1731,7 +1731,7 @@ func TestDb_CreateItems(t *testing.T) {
createItems: createFn(),
opt: []Option{
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"resource-public-id": []string{testOplogResourceId},
"op-type": []string{oplog.OpType_OP_TYPE_CREATE.String()},
@@ -1762,7 +1762,7 @@ func TestDb_CreateItems(t *testing.T) {
opt: []Option{
NewOplogMsgs(&[]*oplog.Message{}),
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"resource-public-id": []string{testOplogResourceId},
"op-type": []string{oplog.OpType_OP_TYPE_CREATE.String()},
@@ -1789,7 +1789,7 @@ func TestDb_CreateItems(t *testing.T) {
createItems: createFn(),
opt: []Option{
WithOplog(
wrapper,
oplogWrapper,
nil,
),
},
@@ -1890,7 +1890,7 @@ func TestDb_CreateItems(t *testing.T) {
func TestDb_DeleteItems(t *testing.T) {
db, _ := TestSetup(t, "postgres")
TestCreateTables(t, db)
wrapper := TestDBWrapper(t, db, "oplog")
oplogWrapper := TestOplogWrapper(t, db)
testOplogResourceId := testId(t)
createFn := func() []any {
@@ -1947,7 +1947,7 @@ func TestDb_DeleteItems(t *testing.T) {
opt: []Option{
NewOplogMsgs(&[]*oplog.Message{}),
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"resource-public-id": []string{testOplogResourceId},
"op-type": []string{oplog.OpType_OP_TYPE_DELETE.String()},
@@ -1965,7 +1965,7 @@ func TestDb_DeleteItems(t *testing.T) {
deleteItems: createFn(),
opt: []Option{
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"resource-public-id": []string{testOplogResourceId},
"op-type": []string{oplog.OpType_OP_TYPE_DELETE.String()},
@@ -1984,7 +1984,7 @@ func TestDb_DeleteItems(t *testing.T) {
deleteItems: createFn(),
opt: []Option{
WithOplog(
wrapper,
oplogWrapper,
nil,
),
},
@@ -2379,7 +2379,7 @@ func TestDb_GetTicket(t *testing.T) {
func TestDb_WriteOplogEntryWith(t *testing.T) {
conn, _ := TestSetup(t, "postgres")
TestCreateTables(t, conn)
wrapper := TestDBWrapper(t, conn, "oplog")
oplogWrapper := TestOplogWrapper(t, conn)
w := New(conn)
testCtx := context.Background()
@@ -2421,7 +2421,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
name: "valid",
underlying: conn,
args: args{
wrapper: wrapper,
wrapper: oplogWrapper,
ticket: ticket,
metadata: metadata,
msgs: []*oplog.Message{&createMsg},
@@ -2432,7 +2432,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
name: "valid-multiple",
underlying: conn,
args: args{
wrapper: wrapper,
wrapper: oplogWrapper,
ticket: ticket,
metadata: metadata,
msgs: []*oplog.Message{&createMsg, &createMsg},
@@ -2443,7 +2443,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
name: "missing-ticket",
underlying: conn,
args: args{
wrapper: wrapper,
wrapper: oplogWrapper,
ticket: nil,
metadata: metadata,
msgs: []*oplog.Message{&createMsg},
@@ -2455,7 +2455,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
name: "missing-db",
underlying: nil,
args: args{
wrapper: wrapper,
wrapper: oplogWrapper,
ticket: ticket,
metadata: metadata,
msgs: []*oplog.Message{&createMsg},
@@ -2479,7 +2479,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
name: "nil-metadata",
underlying: conn,
args: args{
wrapper: wrapper,
wrapper: oplogWrapper,
ticket: ticket,
metadata: nil,
msgs: []*oplog.Message{&createMsg},
@@ -2491,7 +2491,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) {
name: "empty-metadata",
underlying: conn,
args: args{
wrapper: wrapper,
wrapper: oplogWrapper,
ticket: ticket,
metadata: oplog.Metadata{},
msgs: []*oplog.Message{&createMsg},
@@ -5,6 +5,7 @@ begin;
truncate table oplog_entry, oplog_metadata;
-- replaced by 76/01_kms_oplog.up.sql and 76/03_kms_oplog.up.sql
alter table oplog_entry
add column key_id kms_private_id not null
constraint kms_data_key_version_fkey
@@ -16,7 +17,8 @@ begin;
references iam_scope (public_id)
on delete cascade
on update cascade;
-- replaced by 76/01_kms_oplog.up.sql
create function insert_oplog_entry() returns trigger
as $$
begin
@@ -0,0 +1,30 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
alter table oplog_entry
drop constraint iam_scope_fkey,
drop constraint kms_data_key_version_fkey;
drop trigger insert_oplog_entry on oplog_entry;
drop function insert_oplog_entry();
-- replaces function defined in 56/01_oplog_key_id_scope_id_truncation.up.sql
create function insert_oplog_entry() returns trigger
as $$
begin
select scope_id into new.scope_id
from kms_oplog_root_key
inner join kms_oplog_data_key on kms_oplog_root_key.private_id = kms_oplog_data_key.root_key_id
inner join kms_oplog_data_key_version on kms_oplog_data_key.private_id = kms_oplog_data_key_version.data_key_id
where kms_oplog_data_key_version.private_id = new.key_id;
return new;
end;
$$ language plpgsql;
comment on function insert_oplog_entry() is
'insert_oplog_entry sets the oplog scope_id based on the key_id';
create trigger insert_oplog_entry before insert on oplog_entry
for each row execute procedure insert_oplog_entry();
commit;
@@ -0,0 +1,30 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
create table kms_oplog_schema_version(
version text not null,
create_time kms_timestamp,
update_time kms_timestamp
);
comment on table kms_oplog_schema_version is
'kms_oplog_schema_version contains the kms schema version for oplog keys';
create unique index kms_oplog_schema_version_one_row
on kms_oplog_schema_version((version is not null));
-- define the immutable fields for kms_root_key (all of them)
create trigger kms_immutable_columns before update on kms_oplog_schema_version
for each row execute procedure kms_immutable_columns('create_time');
create trigger kms_default_create_time_column before insert on kms_oplog_schema_version
for each row execute procedure kms_default_create_time();
create trigger kms_update_time_column before update on kms_oplog_schema_version
for each row execute procedure kms_update_time_column();
insert into kms_oplog_schema_version(version) values('v0.0.1');
commit;
@@ -0,0 +1,159 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
create table kms_oplog_root_key (
private_id kms_private_id primary key,
scope_id kms_scope_id not null unique, -- there can only be one root key for a scope.
-- intentionally, not creating a FK to iam_scope
create_time kms_timestamp
);
comment on table kms_oplog_root_key is
'kms_oplog_root_key defines a root key for an oplog scope';
-- define the immutable fields for kms_oplog_root_key (all of them)
create trigger kms_immutable_columns before update on kms_oplog_root_key
for each row execute procedure kms_immutable_columns('private_id', 'scope_id', 'create_time');
-- not adding the kms_default_create_time_column trigger until after we've
-- converted the data (we don't want the timestamp to change)
create table kms_oplog_root_key_version (
private_id kms_private_id primary key,
root_key_id kms_private_id not null
constraint kms_oplog_root_key_fkey
references kms_oplog_root_key(private_id)
on delete cascade
on update cascade,
version kms_version,
key bytea not null
constraint not_empty_key
check (
length(key) > 0
),
create_time kms_timestamp,
constraint kms_oplog_root_key_version_root_key_id_version_uq
unique(root_key_id, version)
);
comment on table kms_oplog_root_key_version is
'kms_oplog_root_key_version contains versions of a kms_oplog_root_key';
-- define the immutable fields for kms_root_key_version (all of them)
create trigger kms_immutable_columns before update on kms_oplog_root_key_version
for each row execute procedure kms_immutable_columns('private_id', 'root_key_id', 'create_time');
-- not adding the kms_default_create_time_column or kms_version_column triggers
-- until after we've converted the data (we don't want the timestamp or versions
-- to change)
create table kms_oplog_data_key (
private_id kms_private_id primary key,
root_key_id kms_private_id not null
constraint kms_oplog_root_key_fkey
references kms_oplog_root_key(private_id)
on delete cascade
on update cascade,
purpose text not null
constraint not_start_end_whitespace_purpose
check (length(trim(purpose)) = length(purpose)),
create_time kms_timestamp,
constraint kms_oplog_data_key_root_key_id_purpose_uq
unique (root_key_id, purpose) -- there can only be one dek for a specific purpose per root key
);
comment on table kms_oplog_data_key is
'kms_oplog_data_key contains oplog deks (data keys)';
-- define the immutable fields for kms_oplog_data_key (all of them)
create trigger kms_immutable_columns before update on kms_oplog_data_key
for each row execute procedure kms_immutable_columns('private_id', 'root_key_id', 'purpose', 'create_time');
-- not adding the kms_default_create_time_column trigger until after we've
-- converted the data (we don't want the timestamp to change)
create table kms_oplog_data_key_version (
private_id kms_private_id primary key,
data_key_id kms_private_id not null
constraint kms_oplog_data_key_fkey
references kms_oplog_data_key(private_id)
on delete cascade
on update cascade,
root_key_version_id kms_private_id not null
constraint kms_oplog_root_key_version_fkey
references kms_oplog_root_key_version(private_id)
on delete cascade
on update cascade,
version kms_version,
key bytea not null
constraint not_empty_key
check (
length(key) > 0
),
create_time kms_timestamp,
constraint kms_oplog_data_key_version_data_key_id_version_uq
unique(data_key_id, version)
);
comment on table kms_oplog_data_key_version is
'kms_oplog_data_key_version contains versions of a kms_oplog_data_key (dek aka data keys)';
-- define the immutable fields for kms_oplog_data_key_version (all of them)
create trigger kms_immutable_columns before update on kms_oplog_data_key_version
for each row execute procedure kms_immutable_columns('private_id', 'data_key_id', 'create_time');
-- not adding the kms_default_create_time_column or kms_version_column triggers
-- until after we've converted the data (we don't want the timestamp or versions
-- to change)
-- ############################################################################
-- Next: we will convert all the existing oplog DEK into the new schema model
-- before adding triggers for create_time, and version
-- this is important, especially for the version column!
-- convert KEK tables
insert into kms_oplog_root_key (private_id, scope_id, create_time)
select private_id, scope_id, create_time
from kms_root_key;
insert into kms_oplog_root_key_version (private_id, root_key_id, version, key, create_time)
select private_id, root_key_id, version, key, create_time
from kms_root_key_version;
-- convert oplog DEKs
insert into kms_oplog_data_key (private_id, root_key_id, purpose, create_time)
select private_id, root_key_id, 'oplog', create_time
from kms_data_key where purpose = 'oplog';
insert into kms_oplog_data_key_version (private_id, data_key_id, root_key_version_id, version, key, create_time)
select kdkv.private_id, kdkv.data_key_id, kdkv.root_key_version_id, kdkv.version, kdkv.key, kdkv.create_time
from kms_data_key_version kdkv, kms_oplog_data_key kodk
where kdkv.data_key_id = kodk.private_id;
-- ############################################################################
-- post conversion, we add the required constraints and triggers
alter table oplog_entry
add constraint kms_oplog_data_key_version_fkey
foreign key(key_id)
references kms_oplog_data_key_version (private_id)
on delete restrict
on update cascade;
create trigger kms_default_create_time_column before insert on kms_oplog_root_key
for each row execute procedure kms_default_create_time();
create trigger kms_default_create_time_column before insert on kms_oplog_root_key_version
for each row execute procedure kms_default_create_time();
create trigger kms_version_column before insert on kms_oplog_root_key_version
for each row execute procedure kms_version_column('root_key_id');
create trigger default_create_time_column before insert on kms_oplog_data_key
for each row execute procedure kms_default_create_time();
create trigger default_create_time before insert on kms_oplog_data_key_version
for each row execute procedure kms_default_create_time();
create trigger kms_version_column before insert on kms_oplog_data_key_version
for each row execute procedure kms_version_column('data_key_id');
commit;
@@ -0,0 +1,28 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
create table kms_oplog_collection_version (
version kms_version,
create_time kms_timestamp not null default current_timestamp,
update_time kms_timestamp not null default current_timestamp
);
comment on table kms_oplog_collection_version is
'kms_oplog_collection_version is a single-row table which stores the current version of the kms collection';
-- ensure that it's only ever one row
create unique index kms_oplog_collection_version_one_row
on kms_oplog_collection_version((version is not null));
create trigger kms_immutable_columns before update on kms_oplog_collection_version
for each row execute procedure kms_immutable_columns('create_time');
create trigger kms_update_time_column before update on kms_oplog_collection_version
for each row execute procedure kms_update_time_column();
insert into kms_oplog_collection_version(version) values(1);
update kms_oplog_schema_version set version = 'v0.0.2';
commit;
@@ -1,386 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oss_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/credential/static"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/iam/store"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/testing/dbtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMigrations_Credential_Purpose_Refactor(t *testing.T) {
const (
priorMigration = 39002
currentMigration = 40001
)
t.Parallel()
ctx := context.Background()
dialect := dbtest.Postgres
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c())
})
d, err := common.SqlOpen(dialect, u)
require.NoError(t, err)
// migration to the prior migration (before the one we want to test)
m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err := m.CurrentState(ctx)
require.NoError(t, err)
want := &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: priorMigration,
DatabaseSchemaVersion: priorMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Get a connection
dbType, err := db.StringToDbType(dialect)
require.NoError(t, err)
conn, err := db.Open(ctx, dbType, u)
require.NoError(t, err)
rw := db.New(conn)
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
authRepo, err := authtoken.NewRepository(ctx, rw, rw, kmsCache)
require.NoError(t, err)
uId := "u_1234567890"
oId := "o_1234567890"
pId := "p_1234567890"
accId := "acct_1234567890"
num, err := rw.Exec(ctx, `
insert into iam_scope
(public_id, type, parent_id)
values
(?, ?, ?)
`, []any{oId, "org", "global"})
require.NoError(t, err)
assert.Equal(t, 1, num)
require.NoError(t, kmsCache.CreateKeys(ctx, oId))
num, err = rw.Exec(ctx, `
insert into iam_scope
(public_id, type, parent_id)
values
(?, ?, ?)
`, []any{pId, "project", oId})
require.NoError(t, err)
assert.Equal(t, 1, num)
require.NoError(t, kmsCache.CreateKeys(ctx, pId))
_, err = rw.DoTx(ctx, 0, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
_, err := w.Exec(ctx, `
insert into auth_password_argon2_conf
(private_id, password_method_id)
values
(?, ?)
`, []any{"arg2conf_kWA0RG11DL", "ampw_1234567890"})
if err != nil {
return err
}
_, err = w.Exec(ctx, `
insert into auth_password_method
(public_id, password_conf_id, scope_id)
values
(?, ?, ?)
`, []any{"ampw_1234567890", "arg2conf_kWA0RG11DL", oId})
return err
})
require.NoError(t, err)
num, err = rw.Exec(ctx, `
insert into auth_password_account
(public_id, auth_method_id, scope_id, login_name)
values
(?, ?, ?, ?)
`, []any{"acctpw_1234567890", "ampw_1234567890", oId, "name1"})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
insert into iam_user
(public_id, scope_id)
values
(?, ?)
`, []any{uId, oId})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
insert into auth_account
(public_id, scope_id, auth_method_id, iam_user_id, iam_user_scope_id)
values
(?, ?, ?, ?, ?)
`, []any{accId, oId, "ampw_1234567890", uId, oId})
require.NoError(t, err)
assert.Equal(t, 1, num)
user := &iam.User{
User: &store.User{
PublicId: uId,
},
}
require.NoError(t, rw.LookupById(ctx, user))
at, err := authRepo.CreateAuthToken(ctx, user, accId)
require.NoError(t, err)
// Create host catalog
hostCatalogId := "hcst_s1P81LMusN"
num, err = rw.Exec(ctx, `
insert into static_host_catalog
(scope_id, public_id, name)
values
(?, ?, ?)
`, []any{pId, hostCatalogId, "my-host-catalog"})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create host-set
hostSetId := "hsst_pff4ao7PjN"
num, err = rw.Exec(ctx, `
insert into static_host_set
(public_id, catalog_id)
values
(?, ?)
`, []any{hostSetId, hostCatalogId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create host
hostId := "hst_kDvWAAHBx8"
num, err = rw.Exec(ctx, `
insert into static_host
(public_id, catalog_id, address)
values
(?, ?, ?)
`, []any{hostId, hostCatalogId, "0.0.0.0"})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Associate host to host-set
num, err = rw.Exec(ctx, `
insert into static_host_set_member
(host_id, set_id)
values
(?, ?)
`, []any{hostId, hostSetId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create a target
targetId := "ttcp_JunMRz380q"
num, err = rw.Exec(ctx, `
insert into target_tcp
(public_id, scope_id, name, session_max_seconds, session_connection_limit)
values
(?, ?, ?, ?, ?);
`, []any{targetId, pId, "my-credential-sources", 28800, -1})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create a credential vault store
vaultStoreId := "csvlt_vaultid123"
num, err = rw.Exec(ctx, `
insert into credential_vault_store
(public_id, scope_id, vault_address)
values
(?, ?, ?);
`, []any{vaultStoreId, pId, "http://vault"})
require.NoError(t, err)
assert.Equal(t, 1, num)
credLibs := vault.TestCredentialLibraries(t, conn, wrapper, vaultStoreId, 2)
lib1 := credLibs[0]
lib2 := credLibs[1]
// Create static store
staticStoreId := "csst_staticid123"
num, err = rw.Exec(ctx, `
insert into credential_static_store
(public_id, scope_id, name)
values
(?, ?, ?)
`, []any{staticStoreId, pId, "my-static-credential-store"})
require.NoError(t, err)
assert.Equal(t, 1, num)
credsStatic := static.TestUsernamePasswordCredentials(t, conn, wrapper, "u", "p", staticStoreId, pId, 2)
cred1 := credsStatic[0]
cred2 := credsStatic[1]
appCredLib, err := target.NewCredentialLibrary(ctx, targetId, lib1.GetPublicId(), "application")
require.NoError(t, err)
egressCredLib, err := target.NewCredentialLibrary(ctx, targetId, lib2.GetPublicId(), "egress")
require.NoError(t, err)
appCred, err := target.NewStaticCredential(ctx, targetId, cred1.PublicId, "application")
require.NoError(t, err)
egressCred, err := target.NewStaticCredential(ctx, targetId, cred2.PublicId, "egress")
require.NoError(t, err)
err = rw.CreateItems(ctx, []any{appCredLib, egressCredLib})
require.NoError(t, err)
err = rw.CreateItems(ctx, []any{appCred, egressCred})
require.NoError(t, err)
dynCreds := []*session.DynamicCredential{
session.NewDynamicCredential(appCredLib.GetCredentialLibraryId(), "application"),
session.NewDynamicCredential(egressCredLib.GetCredentialLibraryId(), "egress"),
}
staticCreds := []*session.StaticCredential{
session.NewStaticCredential(appCred.GetCredentialId(), "application"),
session.NewStaticCredential(egressCred.GetCredentialId(), "egress"),
}
// Associate host-set to target
num, err = rw.Exec(ctx, `
insert into target_host_set
(target_id, host_set_id)
values
(?, ?)
`, []any{targetId, hostSetId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create a test session
sessionId := "s_AgLzPhDINE"
future := time.Now().Add(time.Hour)
expirationTime := fmt.Sprintf("%v-%d-%v %v:%v:%v.000", future.Year(), future.Month(), future.Day(), future.Hour(), future.Minute(), future.Second())
_, cert, err := session.TestCert(sessionId)
require.NoError(t, err)
num, err = rw.Exec(ctx, `
insert into session
(public_id, user_id, host_id, target_id, host_set_id, auth_token_id, scope_id, certificate, expiration_time, endpoint)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, []any{sessionId, uId, hostId, targetId, hostSetId, at.GetPublicId(), pId, cert, expirationTime, "tcp://127.0.0.1:22"})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
insert into session_credential_dynamic
(session_id, library_id, credential_purpose)
values
(?, ?, ?),
(?, ?, ?);
`, []any{
sessionId, dynCreds[0].LibraryId, dynCreds[0].CredentialPurpose,
sessionId, dynCreds[1].LibraryId, dynCreds[1].CredentialPurpose,
})
require.NoError(t, err)
assert.Equal(t, 2, num)
num, err = rw.Exec(ctx, `
insert into session_credential_static
(session_id, credential_static_id, credential_purpose)
values
(?, ?, ?),
(?, ?, ?);
`, []any{
sessionId, staticCreds[0].CredentialStaticId, staticCreds[0].CredentialPurpose,
sessionId, staticCreds[1].CredentialStaticId, staticCreds[1].CredentialPurpose,
})
require.NoError(t, err)
assert.Equal(t, 2, num)
// now we're ready for the migration we want to test.
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err = m.CurrentState(ctx)
require.NoError(t, err)
want = &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: currentMigration,
DatabaseSchemaVersion: currentMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Validate migrations
lookupLib := &target.CredentialLibrary{}
err = rw.LookupWhere(ctx, lookupLib, "credential_library_id = ?", []any{appCredLib.GetCredentialLibraryId()})
require.NoError(t, err)
assert.Equal(t, "brokered", lookupLib.CredentialPurpose)
lookupLib = &target.CredentialLibrary{}
err = rw.LookupWhere(ctx, lookupLib, "credential_library_id = ?", []any{egressCredLib.GetCredentialLibraryId()})
require.NoError(t, err)
assert.Equal(t, "injected_application", lookupLib.CredentialPurpose)
lookupCred := &target.StaticCredential{}
err = rw.LookupWhere(ctx, lookupCred, "credential_static_id = ?", []any{appCred.GetCredentialId()})
require.NoError(t, err)
assert.Equal(t, "brokered", lookupCred.CredentialPurpose)
lookupCred = &target.StaticCredential{}
err = rw.LookupWhere(ctx, lookupCred, "credential_static_id = ?", []any{egressCred.GetCredentialId()})
require.NoError(t, err)
assert.Equal(t, "injected_application", lookupCred.CredentialPurpose)
lookupDynCred := &session.DynamicCredential{}
err = rw.LookupWhere(ctx, lookupDynCred, "session_id = ? and library_id = ?", []any{sessionId, appCredLib.GetCredentialLibraryId()})
require.NoError(t, err)
assert.Equal(t, "brokered", lookupDynCred.CredentialPurpose)
lookupDynCred = &session.DynamicCredential{}
err = rw.LookupWhere(ctx, lookupDynCred, "session_id = ? and library_id = ?", []any{sessionId, egressCredLib.GetCredentialLibraryId()})
require.NoError(t, err)
assert.Equal(t, "injected_application", lookupDynCred.CredentialPurpose)
lookupStaticCred := &session.StaticCredential{}
err = rw.LookupWhere(ctx, lookupStaticCred, "session_id = ? and credential_static_id = ?", []any{sessionId, appCred.GetCredentialId()})
require.NoError(t, err)
assert.Equal(t, "brokered", lookupStaticCred.CredentialPurpose)
lookupStaticCred = &session.StaticCredential{}
err = rw.LookupWhere(ctx, lookupStaticCred, "session_id = ? and credential_static_id = ?", []any{sessionId, egressCred.GetCredentialId()})
require.NoError(t, err)
assert.Equal(t, "injected_application", lookupStaticCred.CredentialPurpose)
}
@@ -1,163 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oss_test
import (
"context"
"strings"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/testing/dbtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMigrations_DeprecatedGrants(t *testing.T) {
const (
priorMigration = 52001
currentMigration = 53001
)
t.Parallel()
ctx := context.Background()
dialect := dbtest.Postgres
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c())
})
d, err := common.SqlOpen(dialect, u)
require.NoError(t, err)
// migration to the prior migration (before the one we want to test)
m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err := m.CurrentState(ctx)
require.NoError(t, err)
want := &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: priorMigration,
DatabaseSchemaVersion: priorMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Get a connection
dbType, err := db.StringToDbType(dialect)
require.NoError(t, err)
conn, err := db.Open(ctx, dbType, u)
require.NoError(t, err)
rw := db.New(conn)
// Create project
wrapper := db.TestWrapper(t)
iamRepo := iam.TestRepo(t, conn, wrapper)
oId := "o_1234567890"
pId := "p_1234567890"
num, err := rw.Exec(ctx, `
insert into iam_scope
(public_id, type, parent_id)
values
(?, ?, ?)
`, []any{oId, "org", "global"})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
insert into iam_scope
(public_id, type, parent_id)
values
(?, ?, ?)
`, []any{pId, "project", oId})
require.NoError(t, err)
assert.Equal(t, 1, num)
role := iam.TestRole(t, conn, pId)
initialGrants := map[string]bool{
"id=*;type=target;actions=read,authorize-session,add-host-sets,add-host-sets": true,
"id=*;type=target;actions=set-host-sets,update,delete,remove-credential-libraries": true,
"id=*;type=host-set;actions=read,update,set-credential-sources,set-credential-libraries": true,
"id=*;type=target;actions=add-host-sources,remove-host-sets,add-credential-libraries": true,
}
// Insert grants
for grant := range initialGrants {
iam.TestRoleGrant(t, conn, role.GetPublicId(), grant)
}
// Fetch the role
_, _, initialRoleGrants, err := iamRepo.LookupRole(ctx, role.GetPublicId())
require.NoError(t, err)
require.Len(t, initialRoleGrants, len(initialGrants))
// Initial grant check
for _, grant := range initialRoleGrants {
if !initialGrants[grant.RawGrant] {
require.FailNow(t, "raw grant not found", grant.RawGrant)
}
}
// now we're ready for the migration we want to test.
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err = m.CurrentState(ctx)
require.NoError(t, err)
want = &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: currentMigration,
DatabaseSchemaVersion: currentMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
updatedGrants := make(map[string]bool, len(initialGrants))
for grant := range initialGrants {
updatedGrant := strings.ReplaceAll(grant, "add-host-sets", "add-host-sources")
updatedGrant = strings.ReplaceAll(updatedGrant, "set-host-sets", "set-host-sources")
updatedGrant = strings.ReplaceAll(updatedGrant, "remove-host-sets", "remove-host-sources")
updatedGrant = strings.ReplaceAll(updatedGrant, "add-credential-libraries", "add-credential-sources")
updatedGrant = strings.ReplaceAll(updatedGrant, "set-credential-libraries", "set-credential-sources")
updatedGrant = strings.ReplaceAll(updatedGrant, "remove-credential-libraries", "remove-credential-sources")
updatedGrants[updatedGrant] = true
}
// Fetch the role again
_, _, updatedRoleGrants, err := iamRepo.LookupRole(ctx, role.GetPublicId())
require.NoError(t, err)
require.Len(t, updatedRoleGrants, len(updatedGrants))
// Check updated grants
for _, grant := range updatedRoleGrants {
if !updatedGrants[grant.RawGrant] {
require.FailNow(t, "raw grant not found in migrated state", grant.RawGrant)
}
}
}
@@ -1,106 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oss_test
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/testing/dbtest"
"github.com/stretchr/testify/require"
)
func TestMigrations_NewForeignKeys(t *testing.T) {
const (
priorMigration = 56001
currentMigration = 56002
)
t.Parallel()
ctx := context.Background()
dialect := dbtest.Postgres
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c())
})
d, err := common.SqlOpen(dialect, u)
require.NoError(t, err)
// migration to the prior migration (before the one we want to test)
m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err := m.CurrentState(ctx)
require.NoError(t, err)
want := &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: priorMigration,
DatabaseSchemaVersion: priorMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Get a connection
dbType, err := db.StringToDbType(dialect)
require.NoError(t, err)
conn, err := db.Open(ctx, dbType, u)
require.NoError(t, err)
// Create project
wrapper := db.TestWrapper(t)
kmsCache := kms.TestKms(t, conn, wrapper)
err = kmsCache.CreateKeys(ctx, scope.Global.String())
require.NoError(t, err)
// Create a password account
pwam := password.TestAuthMethod(t, conn, "global")
password.TestAccount(t, conn, pwam.PublicId, "user", password.WithPassword("password"))
// Create an auth token
tok := authtoken.TestAuthToken(t, conn, kmsCache, "global")
_ = tok
// now we're ready for the migration we want to test.
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err = m.CurrentState(ctx)
require.NoError(t, err)
want = &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: currentMigration,
DatabaseSchemaVersion: currentMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// As long as there were no errors, the migration succeeded.
}
@@ -1,298 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oss_test
import (
"context"
"crypto/rand"
"testing"
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/testing/dbtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMigrations_DeleteOrphanedAccounts(t *testing.T) {
const (
priorMigration = 56001
currentMigration = 57001
)
t.Parallel()
ctx := context.Background()
dialect := dbtest.Postgres
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c())
})
d, err := common.SqlOpen(dialect, u)
require.NoError(t, err)
// migration to the prior migration (before the one we want to test)
m, err := schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err := m.CurrentState(ctx)
require.NoError(t, err)
want := &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: priorMigration,
DatabaseSchemaVersion: priorMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Get a connection
dbType, err := db.StringToDbType(dialect)
require.NoError(t, err)
conn, err := db.Open(ctx, dbType, u)
require.NoError(t, err)
wrapper := db.TestWrapper(t)
rw := db.New(conn)
kmsCache := kms.TestKms(t, conn, wrapper)
err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
require.NoError(t, err)
// Create the user we will associate accounts with
iamRepo := iam.TestRepo(t, conn, wrapper)
usr, err := iam.NewUser(ctx, scope.Global.String())
require.NoError(t, err)
usr.PublicId = "u_1234567890"
num, err := rw.Exec(ctx, `
insert into iam_user
(public_id, scope_id)
values
(?, ?)
`, []any{usr.PublicId, scope.Global.String()})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Create the accounts we will delete and assert their behavior
pwAm1, err := password.NewAuthMethod(ctx, scope.Global.String())
require.NoError(t, err)
pwAm1.PublicId = "ampw_1234567890"
_, err = rw.DoTx(ctx, 0, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
_, err := w.Exec(ctx, `
insert into auth_password_argon2_conf
(private_id, password_method_id)
values
(?, ?)
`, []any{"arg2conf_1234567890", pwAm1.PublicId})
if err != nil {
return err
}
_, err = w.Exec(ctx, `
insert into auth_password_method
(public_id, password_conf_id, scope_id)
values
(?, ?, ?)
`, []any{pwAm1.PublicId, "arg2conf_1234567890", pwAm1.ScopeId})
return err
})
require.NoError(t, err)
pwAcct1, err := password.NewAccount(ctx, pwAm1.GetPublicId(), password.WithLoginName("account1"), password.WithPassword("password"))
require.NoError(t, err)
pwAcct1.PublicId = "acctpw_1234567890"
num, err = rw.Exec(ctx, `
insert into auth_password_account
(public_id, auth_method_id, scope_id, login_name)
values
(?, ?, ?, ?)
`, []any{pwAcct1.PublicId, pwAm1.PublicId, pwAm1.ScopeId, pwAcct1.LoginName})
require.NoError(t, err)
assert.Equal(t, 1, num)
pwAm2, err := password.NewAuthMethod(ctx, scope.Global.String())
require.NoError(t, err)
pwAm2.PublicId = "ampw_0123456789"
_, err = rw.DoTx(ctx, 0, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
_, err := w.Exec(ctx, `
insert into auth_password_argon2_conf
(private_id, password_method_id)
values
(?, ?)
`, []any{"arg2conf_0123456789", pwAm2.PublicId})
if err != nil {
return err
}
_, err = w.Exec(ctx, `
insert into auth_password_method
(public_id, password_conf_id, scope_id)
values
(?, ?, ?)
`, []any{pwAm2.PublicId, "arg2conf_0123456789", pwAm2.ScopeId})
return err
})
pwAcct2, err := password.NewAccount(ctx, pwAm2.GetPublicId(), password.WithLoginName("account2"), password.WithPassword("password"))
require.NoError(t, err)
pwAcct2.PublicId = "acctpw_0123456789"
num, err = rw.Exec(ctx, `
insert into auth_password_account
(public_id, auth_method_id, scope_id, login_name)
values
(?, ?, ?, ?)
`, []any{pwAcct2.PublicId, pwAm2.PublicId, pwAm2.ScopeId, pwAcct2.LoginName})
require.NoError(t, err)
assert.Equal(t, 1, num)
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), scope.Global.String(), kms.KeyPurposeDatabase)
oidcAm1 := oidc.TestAuthMethod(t, conn, databaseWrapper, scope.Global.String(), oidc.InactiveState, "alice_rp1",
"my-dogs-name", oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice1.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api1.com")[0]))
oidcAm1.PublicId = "amoidc_1234567890"
num, err = rw.Exec(ctx, `
insert into auth_oidc_method
(public_id, scope_id, state, key_id)
values
(?, ?, ?, ?)
`, []any{oidcAm1.PublicId, oidcAm1.ScopeId, oidcAm1.OperationalState, oidcAm1.KeyId})
require.NoError(t, err)
assert.Equal(t, 1, num)
oidcAcct1, err := oidc.NewAccount(ctx, oidcAm1.GetPublicId(), "oidcAcct1")
require.NoError(t, err)
oidcAcct1.PublicId = "acctoidc_0123456789"
num, err = rw.Exec(ctx, `
insert into auth_oidc_account
(public_id, auth_method_id, scope_id, issuer, subject)
values
(?, ?, ?, ?, ?)
`, []any{oidcAcct1.PublicId, oidcAm1.PublicId, oidcAm1.ScopeId, oidcAm1.Issuer, oidcAcct1.Subject})
require.NoError(t, err)
assert.Equal(t, 1, num)
oidcAm2 := oidc.TestAuthMethod(t, conn, databaseWrapper, scope.Global.String(), oidc.InactiveState, "alice_rp2",
"my-dogs-name", oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice2.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api2.com")[0]))
oidcAm2.PublicId = "amoidc_0123456789"
num, err = rw.Exec(ctx, `
insert into auth_oidc_method
(public_id, scope_id, state, key_id)
values
(?, ?, ?, ?)
`, []any{oidcAm2.PublicId, oidcAm2.ScopeId, oidcAm2.OperationalState, oidcAm2.KeyId})
require.NoError(t, err)
assert.Equal(t, 1, num)
oidcAcct2, err := oidc.NewAccount(ctx, oidcAm2.GetPublicId(), "oidcAcct2")
require.NoError(t, err)
oidcAcct2.PublicId = "acctoidc_1234567890"
num, err = rw.Exec(ctx, `
insert into auth_oidc_account
(public_id, auth_method_id, scope_id, issuer, subject)
values
(?, ?, ?, ?, ?)
`, []any{oidcAcct2.PublicId, oidcAm2.PublicId, oidcAm2.ScopeId, oidcAm2.Issuer, oidcAcct2.Subject})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
update auth_account set
iam_user_id=?
where
public_id in (?, ?, ?, ?)
`, []any{
usr.PublicId,
pwAcct1.PublicId, pwAcct2.PublicId, oidcAcct1.PublicId, oidcAcct2.PublicId,
})
require.NoError(t, err)
assert.Equal(t, 4, num)
usr, accts, err := iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{
pwAcct1.GetPublicId(), pwAcct2.GetPublicId(),
oidcAcct1.GetPublicId(), oidcAcct2.GetPublicId(),
}, accts)
num, err = rw.Exec(ctx, `
delete from auth_password_account
where
public_id=?
`, []any{pwAcct1.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
num, err = rw.Exec(ctx, `
delete from auth_oidc_account
where
public_id=?
`, []any{oidcAcct1.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// pwAcct1 is still listed as an account for this user! oh no!
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{
pwAcct1.GetPublicId(), pwAcct2.GetPublicId(),
oidcAcct1.GetPublicId(), oidcAcct2.GetPublicId(),
}, accts)
// now we're ready for the migration we want to test.
m, err = schema.NewManager(ctx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(ctx)
require.NoError(t, err)
state, err = m.CurrentState(ctx)
require.NoError(t, err)
want = &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: currentMigration,
DatabaseSchemaVersion: currentMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// pwAcct1 is no longer listed as an account for this user. Phew!
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{pwAcct2.GetPublicId(), oidcAcct2.GetPublicId()}, accts)
num, err = rw.Exec(ctx, `
delete from auth_password_account
where
public_id=?
`, []any{pwAcct2.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.ElementsMatch(t, []string{oidcAcct2.GetPublicId()}, accts)
num, err = rw.Exec(ctx, `
delete from auth_oidc_account
where
public_id=?
`, []any{oidcAcct2.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
// Deleting the account now removes the association with the user
_, accts, err = iamRepo.LookupUser(ctx, usr.GetPublicId())
require.NoError(t, err)
assert.Empty(t, accts)
}
@@ -0,0 +1,157 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oss_test
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/common"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/testing/dbtest"
wrappingKms "github.com/hashicorp/go-kms-wrapping/extras/kms/v2"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestMigrations_OplogKeyConversion: in this test we'll create a "deprecated"
// kms (where all the deks are in one set of tables), then we'll create keys in
// that kms. After that, we'll create a new style kms (where the oplog deks are
// in separate tables), and we'll read the existing deks. Finally, we'll ensure
// that the orig deks created using the deprecated kms match the deks read from
// the new style kms. If that's successful, we've converted the oplog deks from
// a shared table table space into their own set of tables.
func TestMigrations_OplogKeyConversion(t *testing.T) {
const (
priorMigration = 76001
currentMigration = 77004
)
t.Parallel()
testCtx := context.Background()
dialect := dbtest.Postgres
c, u, _, err := dbtest.StartUsingTemplate(dialect, dbtest.WithTemplate(dbtest.Template1))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c())
})
d, err := common.SqlOpen(dialect, u)
require.NoError(t, err)
// migration to the prior migration (before the one we want to test)
m, err := schema.NewManager(testCtx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": priorMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(testCtx)
require.NoError(t, err)
state, err := m.CurrentState(testCtx)
require.NoError(t, err)
want := &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: priorMigration,
DatabaseSchemaVersion: priorMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// Get a connection
dbType, err := db.StringToDbType(dialect)
require.NoError(t, err)
conn, err := db.Open(testCtx, dbType, u)
require.NoError(t, err)
rootWrapper := db.TestWrapper(t)
// recreate the deprecated kms, where all the DEKs are in the same tables.
deprecatedKms := deprecatedKms(t, conn, rootWrapper)
deprecatedCreateKeys(t, deprecatedKms, "global")
origDeks := make([]wrapping.Wrapper, 0, len(kms.ValidDekPurposes()))
for _, p := range kms.ValidDekPurposes() {
w, err := deprecatedKms.GetWrapper(testCtx, "global", wrappingKms.KeyPurpose(p.String()))
require.NoError(t, err)
origDeks = append(origDeks, w)
}
// now we're ready for the migration we want to test.
m, err = schema.NewManager(testCtx, schema.Dialect(dialect), d, schema.WithEditions(
schema.TestCreatePartialEditions(schema.Dialect(dialect), schema.PartialEditions{"oss": currentMigration}),
))
require.NoError(t, err)
_, err = m.ApplyMigrations(testCtx)
require.NoError(t, err)
state, err = m.CurrentState(testCtx)
require.NoError(t, err)
want = &schema.State{
Initialized: true,
Editions: []schema.EditionState{
{
Name: "oss",
BinarySchemaVersion: currentMigration,
DatabaseSchemaVersion: currentMigration,
DatabaseSchemaState: schema.Equal,
},
},
}
require.Equal(t, want, state)
// create a new internal kms, where the oplog deks are in their own tables.
// Then we'll read the existing DEKs and make sure they match the original DEKs
kmsCache := kms.TestKms(t, conn, rootWrapper)
newDeks := make([]wrapping.Wrapper, 0, len(kms.ValidDekPurposes()))
for _, p := range kms.ValidDekPurposes() {
w, err := kmsCache.GetWrapper(testCtx, "global", p)
require.NoError(t, err)
newDeks = append(newDeks, w)
}
assert.Equal(t, origDeks, newDeks)
}
// deprecatedKms will create a kms that mimics the deprecated kms where all
// the DEKs are in the same tables
func deprecatedKms(t *testing.T, conn *db.DB, rootWrapper wrapping.Wrapper) *wrappingKms.Kms {
t.Helper()
purposes := make([]wrappingKms.KeyPurpose, 0, len(kms.ValidDekPurposes()))
for _, p := range kms.ValidDekPurposes() {
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
}
purposes = append(purposes,
wrappingKms.KeyPurpose(kms.KeyPurposeWorkerAuth.String()),
wrappingKms.KeyPurpose(kms.KeyPurposeWorkerAuthStorage.String()),
wrappingKms.KeyPurpose(kms.KeyPurposeRecovery.String()),
wrappingKms.KeyPurpose(kms.KeyPurposeBsr.String()),
)
rw := db.New(conn)
k, err := wrappingKms.New(db.NewChangeSafeDbwReader(rw), db.NewChangeSafeDbwWriter(rw), purposes)
require.NoError(t, err)
err = k.AddExternalWrapper(context.Background(), wrappingKms.KeyPurposeRootKey, rootWrapper)
require.NoError(t, err)
return k
}
// deprecatedCreateKeys will create deks that are all in the same table
func deprecatedCreateKeys(t *testing.T, k *wrappingKms.Kms, scopeId string) {
t.Helper()
require.NotEmpty(t, scopeId)
purposes := make([]wrappingKms.KeyPurpose, 0, len(kms.ValidDekPurposes()))
for _, p := range kms.ValidDekPurposes() {
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
}
err := k.CreateKeys(context.Background(), scopeId, purposes)
require.NoError(t, err)
}
+5 -10
View File
@@ -135,21 +135,16 @@ func TestWrapper(t testing.TB) wrapping.Wrapper {
return root
}
// TestDBWrapper initializes a DB wrapper for testing
func TestDBWrapper(t testing.TB, conn *DB, purpose kms.KeyPurpose) wrapping.Wrapper {
// TestOplogWrapper initializes a DB wrapper for testing
func TestOplogWrapper(t testing.TB, conn *DB) wrapping.Wrapper {
t.Helper()
purposes := []kms.KeyPurpose{purpose}
if purpose != "oplog" {
// Always add the oplog purpose, most tests need it
purposes = append(purposes, "oplog")
}
kmsCache, err := kms.New(dbw.New(conn.wrapped.Load()), dbw.New(conn.wrapped.Load()), purposes)
kmsCache, err := kms.New(dbw.New(conn.wrapped.Load()), dbw.New(conn.wrapped.Load()), []kms.KeyPurpose{"oplog"}, kms.WithTableNamePrefix("kms_oplog"))
require.NoError(t, err)
err = kmsCache.AddExternalWrapper(context.Background(), kms.KeyPurposeRootKey, TestWrapper(t))
require.NoError(t, err)
err = kmsCache.CreateKeys(context.Background(), "global", purposes)
err = kmsCache.CreateKeys(context.Background(), "global", []kms.KeyPurpose{"oplog"})
require.NoError(t, err)
wrapper, err := kmsCache.GetWrapper(context.Background(), "global", purpose)
wrapper, err := kmsCache.GetWrapper(context.Background(), "global", "oplog")
require.NoError(t, err)
return wrapper
}
+2 -2
View File
@@ -28,7 +28,7 @@ func TestVerifyOplogEntry(t *testing.T) {
d, _ := TestSetup(t, "postgres")
assert := assert.New(t)
TestCreateTables(t, d)
wrapper := TestDBWrapper(t, d, "oplog")
oplogWrapper := TestOplogWrapper(t, d)
t.Run("valid", func(t *testing.T) {
rw := New(d)
@@ -41,7 +41,7 @@ func TestVerifyOplogEntry(t *testing.T) {
context.Background(),
user,
WithOplog(
wrapper,
oplogWrapper,
oplog.Metadata{
"op-type": []string{oplog.OpType_OP_TYPE_CREATE.String()},
"resource-public-id": []string{user.GetPublicId()},
+3
View File
@@ -27,6 +27,9 @@ func TestRewrap_hostCatalogSecretRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
+125 -12
View File
@@ -26,6 +26,7 @@ import (
// caches, going to the database as needed.
type Kms struct {
underlying *wrappingKms.Kms
underlyingForOplog *wrappingKms.Kms // Yep, this kms is only used for oplog DEKs
reader db.Reader
writer db.Writer
derivedPurposeCache sync.Map
@@ -47,10 +48,22 @@ func New(ctx context.Context, reader *db.Db, writer *db.Db, _ ...Option) (*Kms,
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating new in-memory kms"))
}
oplogK, err := wrappingKms.New(
db.NewChangeSafeDbwReader(reader),
db.NewChangeSafeDbwWriter(writer),
[]wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOplog.String())},
wrappingKms.WithTableNamePrefix("kms_oplog"),
)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating new in-memory kms"))
}
return &Kms{
underlying: k,
reader: reader,
writer: writer,
underlying: k,
underlyingForOplog: oplogK,
reader: reader,
writer: writer,
}, nil
}
@@ -78,9 +91,19 @@ func NewUsingReaderWriter(ctx context.Context, reader db.Reader, writer db.Write
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating new in-memory kms"))
}
oplogK, err := wrappingKms.New(
db.NewChangeSafeDbwReader(r),
db.NewChangeSafeDbwWriter(w),
[]wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOplog.String())},
wrappingKms.WithTableNamePrefix("kms_oplog"),
)
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating new in-memory kms"))
}
return &Kms{
underlying: k,
reader: reader,
underlying: k,
underlyingForOplog: oplogK,
reader: reader,
}, nil
}
@@ -93,6 +116,10 @@ func (k *Kms) AddExternalWrappers(ctx context.Context, opt ...Option) error {
if err := k.underlying.AddExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeRootKey.String()), opts.withRootWrapper); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add root wrapper"))
}
// we need this external wrapper for the oplog KMS
if err := k.underlyingForOplog.AddExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeRootKey.String()), opts.withRootWrapper); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("unable to add root wrapper to kms_oplog"))
}
}
if opts.withWorkerAuthWrapper != nil {
if err := k.underlying.AddExternalWrapper(ctx, wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()), opts.withWorkerAuthWrapper); err != nil {
@@ -125,7 +152,14 @@ func (k *Kms) GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing purpose")
}
opts := getOpts(opt...)
w, err := k.underlying.GetWrapper(ctx, scopeId, wrappingKms.KeyPurpose(purpose.String()), wrappingKms.WithKeyId(opts.withKeyId))
var underlying *wrappingKms.Kms
switch purpose {
case KeyPurposeOplog:
underlying = k.underlyingForOplog
default:
underlying = k.underlying
}
w, err := underlying.GetWrapper(ctx, scopeId, wrappingKms.KeyPurpose(purpose.String()), wrappingKms.WithKeyId(opts.withKeyId))
if err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get wrapper"))
}
@@ -200,7 +234,7 @@ func (k *Kms) ReconcileKeys(ctx context.Context, randomReader io.Reader, opt ...
// transaction which allows this capability to be shared with the iam repo when
// it's creating Scopes.
func (k *Kms) CreateKeys(ctx context.Context, scopeId string, opt ...Option) error {
const op = "kms.(Kms).CreateKeysTx"
const op = "kms.(Kms).CreateKeys"
if scopeId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
}
@@ -222,12 +256,62 @@ func (k *Kms) CreateKeys(ctx context.Context, scopeId string, opt ...Option) err
}
kmsOpts = append(kmsOpts, wrappingKms.WithReaderWriter(db.NewChangeSafeDbwReader(r), db.NewChangeSafeDbwWriter(w)))
}
purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes()))
purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes())-1) // -1 because it's all of the DEKs except for the oplog DEK
for _, p := range ValidDekPurposes() {
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
switch p {
case KeyPurposeOplog:
continue
default:
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
}
}
if err := k.underlying.CreateKeys(ctx, scopeId, purposes, kmsOpts...); err != nil {
return errors.Wrap(ctx, err, op)
{
switch {
case isNil(opts.withWriter) && isNil(opts.withReader):
// it appears we don't have an inflight transaction, so we'll create
// our own to ensure that all keys are created successfully or
// they're rolled back.
_, err := k.writer.DoTx(ctx, db.StdRetryCnt,
db.ExpBackoff{},
func(txReader db.Reader, txWriter db.Writer) error {
r, ok := txReader.(*db.Db)
if !ok {
return errors.New(ctx, errors.InvalidParameter, op, "unable to convert reader to db.Db")
}
w, ok := txWriter.(*db.Db)
if !ok {
return errors.New(ctx, errors.InvalidParameter, op, "unable to convert writer to db.Db")
}
kmsOpts = append(kmsOpts,
wrappingKms.WithRandomReader(opts.withRandomReader),
wrappingKms.WithReaderWriter(
db.NewChangeSafeDbwReader(r),
db.NewChangeSafeDbwWriter(w),
),
)
if err := k.underlying.CreateKeys(ctx, scopeId, purposes, kmsOpts...); err != nil {
return err
}
if err := k.underlyingForOplog.CreateKeys(ctx, scopeId, []wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOplog.String())}, kmsOpts...); err != nil {
return err
}
return nil
})
if err != nil {
return errors.Wrap(ctx, err, op)
}
default:
// it appears we have an inflight transaction, so we can just
// make multiple calls to CreateKeys(...) and let the caller's
// transaction rollback when needed.
if err := k.underlying.CreateKeys(ctx, scopeId, purposes, kmsOpts...); err != nil {
return errors.Wrap(ctx, err, op)
}
if err := k.underlyingForOplog.CreateKeys(ctx, scopeId, []wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOplog.String())}, kmsOpts...); err != nil {
return errors.Wrap(ctx, err, op)
}
}
}
return nil
}
@@ -243,6 +327,18 @@ func (k *Kms) ListKeys(ctx context.Context, scopeId string, _ ...Option) ([]wrap
}
return nil, errors.Wrap(ctx, err, op)
}
oplogKeys, err := k.underlyingForOplog.ListKeys(ctx, scopeId)
if err != nil {
if errors.Is(err, dbw.ErrRecordNotFound) {
return nil, errors.E(ctx, errors.WithCode(errors.RecordNotFound), errors.WithOp(op))
}
return nil, errors.Wrap(ctx, err, op)
}
for _, k := range oplogKeys {
if k.Purpose == wrappingKms.KeyPurpose(KeyPurposeOplog.String()) {
keys = append(keys, k)
}
}
return keys, nil
}
@@ -280,6 +376,10 @@ func (k *Kms) RotateKeys(ctx context.Context, scopeId string, opt ...Option) err
if err != nil {
return errors.Wrap(ctx, err, op)
}
err = k.underlyingForOplog.RotateKeys(ctx, scopeId, kmsOpts...)
if err != nil {
return errors.Wrap(ctx, err, op)
}
return nil
}
@@ -600,7 +700,12 @@ func (k *Kms) VerifyGlobalRoot(ctx context.Context) error {
func stdNewKmsPurposes() []wrappingKms.KeyPurpose {
purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes()))
for _, p := range ValidDekPurposes() {
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
switch p {
case KeyPurposeOplog:
continue
default:
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
}
}
purposes = append(purposes,
wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()),
@@ -629,3 +734,11 @@ type rootKey struct {
}
func (*rootKey) TableName() string { return "kms_root_key" }
type rootOplogKey struct {
PrivateId string `gorm:"primary_key"`
ScopeId string `gorm:"default:null"`
CreateTime time.Time `gorm:"default:current_timestamp"`
}
func (*rootOplogKey) TableName() string { return "kms_oplog_root_key" }
+28 -2
View File
@@ -54,7 +54,12 @@ func Test_New(t *testing.T) {
underlying: func() *wrappingKms.Kms {
purposes := make([]wrappingKms.KeyPurpose, 0, len(ValidDekPurposes()))
for _, p := range ValidDekPurposes() {
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
switch p {
case KeyPurposeOplog:
continue
default:
purposes = append(purposes, wrappingKms.KeyPurpose(p.String()))
}
}
purposes = append(purposes,
wrappingKms.KeyPurpose(KeyPurposeWorkerAuth.String()),
@@ -67,6 +72,16 @@ func Test_New(t *testing.T) {
require.NoError(t, err)
return wrapped
}(),
underlyingForOplog: func() *wrappingKms.Kms {
wrapped, err := wrappingKms.New(
db.NewChangeSafeDbwReader(rw),
db.NewChangeSafeDbwWriter(rw),
[]wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOplog.String())},
wrappingKms.WithTableNamePrefix("kms_oplog"),
)
require.NoError(t, err)
return wrapped
}(),
},
},
}
@@ -148,6 +163,16 @@ func Test_NewUsingReaderWriter(t *testing.T) {
require.NoError(t, err)
return wrapped
}(),
underlyingForOplog: func() *wrappingKms.Kms {
wrapped, err := wrappingKms.New(
db.NewChangeSafeDbwReader(rw),
db.NewChangeSafeDbwWriter(rw),
[]wrappingKms.KeyPurpose{wrappingKms.KeyPurpose(KeyPurposeOplog.String())},
wrappingKms.WithTableNamePrefix("kms_oplog"),
)
require.NoError(t, err)
return wrapped
}(),
},
},
}
@@ -802,9 +827,10 @@ func TestDestroyKeyVersion(t *testing.T) {
kvToDestroy = key.Versions[0]
}
}
require.NotEmpty(t, kvToDestroy.Id)
_, err := kmsCache.DestroyKeyVersion(testCtx, "global", kvToDestroy.Id)
require.Error(t, err)
assert.True(t, errors.Match(errors.T(errors.InvalidParameter), err))
assert.True(t, errors.Match(errors.T(errors.KeyNotFound), err))
})
t.Run("succeeds-synchronously-when-destroying-old-root-key-version", func(t *testing.T) {
var chosenKey wrappingKms.Key
+1
View File
@@ -37,6 +37,7 @@ func TestKmsDeleteKeyPurpose(t testing.TB, conn *db.DB, purpose KeyPurpose) {
func TestKmsDeleteAllKeys(t testing.TB, conn *db.DB) {
oplog.TestOplogDeleteAllEntries(t, db.New(conn).UnderlyingDB()())
db.TestDeleteWhere(t, conn, func() any { i := rootKey{}; return &i }(), "1=1")
db.TestDeleteWhere(t, conn, func() any { i := rootOplogKey{}; return &i }(), "1=1")
}
type dataKey struct{}
+1 -1
View File
@@ -51,7 +51,7 @@ func setup(ctx context.Context, t testing.TB) (*dbw.DB, wrapping.Wrapper) {
require.NoError(err)
r := dbw.New(db)
w := dbw.New(db)
kmsCache, err := kms.New(r, w, []kms.KeyPurpose{kms.KeyPurposeRootKey, "oplog"})
kmsCache, err := kms.New(r, w, []kms.KeyPurpose{kms.KeyPurposeRootKey, "oplog"}, kms.WithTableNamePrefix("kms_oplog"))
require.NoError(err)
err = kmsCache.AddExternalWrapper(ctx, kms.KeyPurposeRootKey, root)
require.NoError(err)
@@ -1060,6 +1060,7 @@ func TestRepository_CreateWorker(t *testing.T) {
repo: func() *server.Repository {
mockConn, mock := db.TestSetupWithMock(t)
mock.ExpectQuery(`SELECT`).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(`SELECT`).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(`SELECT`).WillReturnError(errors.New(testCtx, errors.Internal, "test", "no-database-key"))
k := kms.TestKms(t, mockConn, wrapper)
r, err := server.NewRepository(testCtx, rw, rw, k)
+9
View File
@@ -29,6 +29,9 @@ func TestRewrap_workerAuthCertRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -85,6 +88,9 @@ func TestRewrap_workerAuthRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -142,6 +148,9 @@ func TestRewrap_workerAuthServerLedActivationTokenRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
+6
View File
@@ -30,6 +30,9 @@ func TestRewrap_sessionCredentialRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -118,6 +121,9 @@ func TestRewrap_sessionRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(
@@ -30,6 +30,9 @@ func TestRewrap_storageBucketSecretRewrapFn(t *testing.T) {
mock.ExpectQuery(
`SELECT \* FROM "kms_schema_version" WHERE 1=1 ORDER BY "kms_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
mock.ExpectQuery(
`SELECT \* FROM "kms_oplog_schema_version" WHERE 1=1 ORDER BY "kms_oplog_schema_version"\."version" LIMIT 1`,
).WillReturnRows(sqlmock.NewRows([]string{"version", "create_time"}).AddRow(migrations.Version, time.Now()))
kmsCache := kms.TestKms(t, conn, wrapper)
rw := db.New(conn)
mock.ExpectQuery(