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:
31 files changed
+733
-1943
No files matched your search
@@ -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
|
||||
)
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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},
|
||||
|
||||
+3
-1
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()},
|
||||
|
||||
@@ -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
@@ -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" }
|
||||
@@ -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
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in new issue
Block a user