From ca35cfb83b165155a0cb6e0d663b6016526a624a Mon Sep 17 00:00:00 2001 From: Arne Luenser Date: Wed, 14 Feb 2024 13:58:07 +0100 Subject: [PATCH] feat: change primary key on identity_verifiable_addresses and identity_recovery_addresses --- driver/registry.go | 62 ++++++++-------- driver/registry_default.go | 5 +- go.mod | 2 +- go.sum | 1 - persistence/sql/migratest/migration_test.go | 29 ++++---- .../migrations/gomigrations/identity_pk.go | 71 +++++++++++++++++++ ...000000_unique_credentials.sqlite3.down.sql | 3 +- ...ity_verifiable_addresses_pk.mysql.down.sql | 7 ++ ...ntity_verifiable_addresses_pk.mysql.up.sql | 4 ++ ..._verifiable_addresses_pk.postgres.down.sql | 3 + ...ty_verifiable_addresses_pk.postgres.up.sql | 17 +++++ ...ty_verifiable_addresses_pk.sqlite.down.sql | 27 +++++++ ...tity_verifiable_addresses_pk.sqlite.up.sql | 30 ++++++++ ...ntity_recovery_addresses_pk.mysql.down.sql | 24 +++++++ ...dentity_recovery_addresses_pk.mysql.up.sql | 20 ++++++ ...ty_recovery_addresses_pk.postgres.down.sql | 3 + ...tity_recovery_addresses_pk.postgres.up.sql | 17 +++++ ...tity_recovery_addresses_pk.sqlite.down.sql | 25 +++++++ ...entity_recovery_addresses_pk.sqlite.up.sql | 26 +++++++ persistence/sql/persister.go | 28 +++++--- 20 files changed, 345 insertions(+), 59 deletions(-) create mode 100644 persistence/sql/migrations/gomigrations/identity_pk.go create mode 100644 persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.down.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.down.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.up.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.down.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.up.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.down.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.up.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.down.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.up.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.down.sql create mode 100644 persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.up.sql diff --git a/driver/registry.go b/driver/registry.go index dc31f7305633..541b7eb3abff 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -7,45 +7,39 @@ import ( "context" "io/fs" - "github.com/ory/kratos/selfservice/sessiontokenexchange" - "github.com/ory/x/contextx" - "github.com/ory/x/jsonnetsecure" - "github.com/ory/x/otelx" - prometheus "github.com/ory/x/prometheusx" - "github.com/gorilla/sessions" "github.com/pkg/errors" - "github.com/ory/nosurf" - - "github.com/ory/x/logrusx" - + "github.com/ory/kratos/cipher" "github.com/ory/kratos/continuity" "github.com/ory/kratos/courier" + "github.com/ory/kratos/driver/config" "github.com/ory/kratos/hash" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/persistence" "github.com/ory/kratos/schema" + "github.com/ory/kratos/selfservice/errorx" + "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/selfservice/flow/logout" "github.com/ory/kratos/selfservice/flow/recovery" + "github.com/ory/kratos/selfservice/flow/registration" "github.com/ory/kratos/selfservice/flow/settings" "github.com/ory/kratos/selfservice/flow/verification" + "github.com/ory/kratos/selfservice/sessiontokenexchange" "github.com/ory/kratos/selfservice/strategy/code" "github.com/ory/kratos/selfservice/strategy/link" - - "github.com/ory/x/healthx" - - "github.com/ory/kratos/persistence" - "github.com/ory/kratos/selfservice/flow/login" - "github.com/ory/kratos/selfservice/flow/logout" - "github.com/ory/kratos/selfservice/flow/registration" - - "github.com/ory/kratos/x" - - "github.com/ory/x/dbal" - - "github.com/ory/kratos/driver/config" - "github.com/ory/kratos/identity" - "github.com/ory/kratos/selfservice/errorx" password2 "github.com/ory/kratos/selfservice/strategy/password" "github.com/ory/kratos/session" + "github.com/ory/kratos/x" + "github.com/ory/nosurf" + "github.com/ory/x/contextx" + "github.com/ory/x/dbal" + "github.com/ory/x/healthx" + "github.com/ory/x/jsonnetsecure" + "github.com/ory/x/logrusx" + "github.com/ory/x/otelx" + "github.com/ory/x/popx" + prometheus "github.com/ory/x/prometheusx" ) type Registry interface { @@ -85,6 +79,8 @@ type Registry interface { continuity.ManagementProvider continuity.PersistenceProvider + cipher.Provider + courier.Provider persistence.Provider @@ -186,10 +182,12 @@ type options struct { replaceIdentitySchemaProvider func(Registry) schema.IdentitySchemaProvider inspect func(Registry) error extraMigrations []fs.FS - replacementStrategies []NewStrategy - extraHooks map[string]func(config.SelfServiceHook) any - disableMigrationLogging bool - jsonnetPool jsonnetsecure.Pool + extraGoMigrations popx.Migrations + + replacementStrategies []NewStrategy + extraHooks map[string]func(config.SelfServiceHook) any + disableMigrationLogging bool + jsonnetPool jsonnetsecure.Pool } type RegistryOption func(*options) @@ -251,6 +249,12 @@ func WithExtraMigrations(m ...fs.FS) RegistryOption { } } +func WithExtraGoMigrations(m ...popx.Migration) RegistryOption { + return func(o *options) { + o.extraGoMigrations = append(o.extraGoMigrations, m...) + } +} + func WithDisabledMigrationLogging() RegistryOption { return func(o *options) { o.disableMigrationLogging = true diff --git a/driver/registry_default.go b/driver/registry_default.go index 9f88c7375dd0..9a89cb052136 100644 --- a/driver/registry_default.go +++ b/driver/registry_default.go @@ -672,7 +672,10 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize m.Logger().WithError(err).Warnf("Unable to open database, retrying.") return errors.WithStack(err) } - p, err := sql.NewPersister(ctx, m, c, sql.WithExtraMigrations(o.extraMigrations...), sql.WithDisabledLogging(o.disableMigrationLogging)) + p, err := sql.NewPersister(ctx, m, c, + sql.WithExtraMigrations(o.extraMigrations...), + sql.WithExtraGoMigrations(o.extraGoMigrations...), + sql.WithDisabledLogging(o.disableMigrationLogging)) if err != nil { m.Logger().WithError(err).Warnf("Unable to initialize persister, retrying.") return err diff --git a/go.mod b/go.mod index ac36ab25892a..61009dc01832 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/jmoiron/sqlx v1.4.0 github.com/julienschmidt/httprouter v1.3.0 github.com/knadh/koanf/parsers/json v0.1.0 - github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 + github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 // indirect github.com/lestrrat-go/jwx/v2 v2.1.1 github.com/luna-duclos/instrumentedsql v1.1.3 github.com/mailhog/MailHog v1.0.1 diff --git a/go.sum b/go.sum index e33a12499ae0..8036e25d5bec 100644 --- a/go.sum +++ b/go.sum @@ -551,7 +551,6 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index bf727683248b..a908704c17be 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -8,30 +8,21 @@ import ( "encoding/json" "os" "path/filepath" + "slices" "sync" "testing" "time" - "github.com/ory/x/pagination/keysetpagination" - "github.com/ory/x/servicelocatorx" - - "github.com/ory/kratos/identity" - "github.com/bradleyjkemp/cupaloy/v2" - "github.com/stretchr/testify/assert" - - "github.com/ory/x/dbal" - - "github.com/ory/kratos/x/xsql" - - "github.com/ory/x/migratest" - "github.com/gobuffalo/pop/v6" "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ory/kratos/driver" "github.com/ory/kratos/driver/config" + "github.com/ory/kratos/identity" + "github.com/ory/kratos/persistence/sql/migrations/gomigrations" "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/selfservice/flow/recovery" "github.com/ory/kratos/selfservice/flow/registration" @@ -41,9 +32,14 @@ import ( "github.com/ory/kratos/selfservice/strategy/link" "github.com/ory/kratos/session" "github.com/ory/kratos/x" + "github.com/ory/kratos/x/xsql" "github.com/ory/x/configx" + "github.com/ory/x/dbal" "github.com/ory/x/logrusx" + "github.com/ory/x/migratest" + "github.com/ory/x/pagination/keysetpagination" "github.com/ory/x/popx" + "github.com/ory/x/servicelocatorx" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlcon/dockertest" ) @@ -87,7 +83,7 @@ func TestMigrations_Postgres(t *testing.T) { t.Skip("skipping testing in short mode") } t.Parallel() - testDatabase(t, "postgres", dockertest.ConnectPop(t, dockertest.RunTestPostgreSQLWithVersion(t, "11.8"))) + testDatabase(t, "postgres", dockertest.ConnectPop(t, dockertest.RunTestPostgreSQLWithVersion(t, "16"))) } func TestMigrations_Mysql(t *testing.T) { @@ -95,7 +91,7 @@ func TestMigrations_Mysql(t *testing.T) { t.Skip("skipping testing in short mode") } t.Parallel() - testDatabase(t, "mysql", dockertest.ConnectPop(t, dockertest.RunTestMySQLWithVersion(t, "8.0.34"))) + testDatabase(t, "mysql", dockertest.ConnectPop(t, dockertest.RunTestMySQLWithVersion(t, "8.0"))) } func TestMigrations_Cockroach(t *testing.T) { @@ -134,6 +130,9 @@ func testDatabase(t *testing.T, db string, c *pop.Connection) { os.DirFS("../migrations/sql"), popx.NewMigrator(c, l, nil, 1*time.Minute), popx.WithTestdata(t, os.DirFS("./testdata")), + popx.WithGoMigrations(slices.Concat( + gomigrations.ChangeAddressesPK, + )), ) require.NoError(t, err) tm.DumpMigrations = true diff --git a/persistence/sql/migrations/gomigrations/identity_pk.go b/persistence/sql/migrations/gomigrations/identity_pk.go new file mode 100644 index 000000000000..05002da790ed --- /dev/null +++ b/persistence/sql/migrations/gomigrations/identity_pk.go @@ -0,0 +1,71 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package gomigrations + +import ( + "fmt" + "path/filepath" + "runtime" + + "github.com/gobuffalo/pop/v6" + "github.com/pkg/errors" + + "github.com/ory/x/popx" +) + +func path() string { + _, file, line, _ := runtime.Caller(1) + return fmt.Sprintf("%s:%d", filepath.Base(file), line) +} + +var ChangeAddressesPK = []popx.Migration{ + { + Version: "20241001000000000000", + Path: path(), + Name: "Change primary key for identity_verifiable_addresses", + Direction: "up", + Type: "go", + DBType: "cockroach", + RunnerNoTx: func(m popx.Migration, c *pop.Connection) error { + _, err := c.Store.Exec("ALTER TABLE identity_verifiable_addresses ALTER PRIMARY KEY USING COLUMNS (identity_id,id)") + return errors.WithStack(err) + }, + }, + { + Version: "20241001000000000000", + Path: path(), + Name: "Revert primary key for identity_verifiable_addresses", + Direction: "down", + Type: "go", + DBType: "cockroach", + RunnerNoTx: func(m popx.Migration, c *pop.Connection) error { + _, err := c.Store.Exec("ALTER TABLE identity_verifiable_addresses ALTER PRIMARY KEY USING COLUMNS (id)") + return errors.WithStack(err) + }, + }, + { + Version: "20241001000000000001", + Path: path(), + Name: "Change primary key for identity_recovery_addresses", + Direction: "up", + Type: "go", + DBType: "cockroach", + RunnerNoTx: func(m popx.Migration, c *pop.Connection) error { + _, err := c.Store.Exec("ALTER TABLE identity_recovery_addresses ALTER PRIMARY KEY USING COLUMNS (identity_id,id)") + return errors.WithStack(err) + }, + }, + { + Version: "20241001000000000001", + Path: path(), + Name: "Revert primary key for identity_recovery_addresses", + Direction: "down", + Type: "go", + DBType: "cockroach", + RunnerNoTx: func(m popx.Migration, c *pop.Connection) error { + _, err := c.Store.Exec("ALTER TABLE identity_recovery_addresses ALTER PRIMARY KEY USING COLUMNS (id)") + return errors.WithStack(err) + }, + }, +} diff --git a/persistence/sql/migrations/sql/20210817181232000000_unique_credentials.sqlite3.down.sql b/persistence/sql/migrations/sql/20210817181232000000_unique_credentials.sqlite3.down.sql index ebb42cf99e00..7d1f91589640 100644 --- a/persistence/sql/migrations/sql/20210817181232000000_unique_credentials.sqlite3.down.sql +++ b/persistence/sql/migrations/sql/20210817181232000000_unique_credentials.sqlite3.down.sql @@ -1 +1,2 @@ -CREATE UNIQUE INDEX "identity_credential_identifiers_identifier_nid_uq_idx" ON "identity_credential_identifiers" (nid, identifier); \ No newline at end of file +DELETE FROM "identity_credential_identifiers"; -- This migration is destructive. +CREATE UNIQUE INDEX "identity_credential_identifiers_identifier_nid_uq_idx" ON "identity_credential_identifiers" (nid, identifier); diff --git a/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.down.sql b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.down.sql new file mode 100644 index 000000000000..91863660ac61 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.down.sql @@ -0,0 +1,7 @@ +ALTER TABLE identity_verifiable_addresses + DROP FOREIGN KEY identity_verifiable_addresses_ibfk_1; + +ALTER TABLE identity_verifiable_addresses + DROP PRIMARY KEY, + ADD PRIMARY KEY (id), + ADD CONSTRAINT identity_verifiable_addresses_ibfk_1 FOREIGN KEY (identity_id) REFERENCES identities(id) ON DELETE CASCADE; diff --git a/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.up.sql b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.up.sql new file mode 100644 index 000000000000..4846713ab1c3 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.mysql.up.sql @@ -0,0 +1,4 @@ +ALTER TABLE identity_verifiable_addresses + DROP PRIMARY KEY, + ADD PRIMARY KEY (identity_id, id), + ADD UNIQUE KEY identity_verifiable_addresses_id_uq_idx (id); diff --git a/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.down.sql b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.down.sql new file mode 100644 index 000000000000..ed3fe5674e96 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE identity_verifiable_addresses + DROP CONSTRAINT identity_verifiable_addresses_pkey, + ADD PRIMARY KEY (id); diff --git a/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.up.sql b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.up.sql new file mode 100644 index 000000000000..67cdda56393c --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.postgres.up.sql @@ -0,0 +1,17 @@ +CREATE UNIQUE INDEX identity_verifiable_addresses_id_uq_idx ON identity_verifiable_addresses (id); + +ALTER TABLE identity_verification_codes + DROP CONSTRAINT identity_verification_codes_identity_verifiable_addresses_id_fk; + +ALTER TABLE identity_verification_tokens + DROP CONSTRAINT identity_verification_tokens_identity_verifiable_address_i_fkey; + +ALTER TABLE identity_verifiable_addresses + DROP CONSTRAINT identity_verifiable_addresses_pkey, + ADD PRIMARY KEY (identity_id, id); + +ALTER TABLE identity_verification_codes + ADD CONSTRAINT identity_verification_codes_identity_verifiable_addresses_id_fk FOREIGN KEY (identity_verifiable_address_id) REFERENCES identity_verifiable_addresses(id) ON DELETE CASCADE; + +ALTER TABLE identity_verification_tokens + ADD CONSTRAINT identity_verification_tokens_identity_verifiable_address_i_fkey FOREIGN KEY (identity_verifiable_address_id) REFERENCES identity_verifiable_addresses(id) ON DELETE CASCADE; diff --git a/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.down.sql b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.down.sql new file mode 100644 index 000000000000..461a5e8fa392 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.down.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS "_identity_verifiable_addresses_tmp" ( +"id" TEXT PRIMARY KEY, +"status" TEXT NOT NULL, +"via" TEXT NOT NULL, +"verified" bool NOT NULL, +"value" TEXT NOT NULL, +"verified_at" DATETIME, +"identity_id" TEXT NOT NULL, +"created_at" DATETIME NOT NULL, +"updated_at" DATETIME NOT NULL, +"nid" TEXT NOT NULL, +FOREIGN KEY ("identity_id") REFERENCES "identities" ("id") ON UPDATE RESTRICT ON DELETE CASCADE, +FOREIGN KEY ("nid") REFERENCES "networks" ("id") ON UPDATE RESTRICT ON DELETE CASCADE +); + +INSERT INTO "_identity_verifiable_addresses_tmp" + ("id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid") +SELECT + "id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid" +FROM "identity_verifiable_addresses"; + +DROP TABLE "identity_verifiable_addresses"; +ALTER TABLE "_identity_verifiable_addresses_tmp" RENAME TO "identity_verifiable_addresses"; + +CREATE UNIQUE INDEX IF NOT EXISTS "identity_verifiable_addresses_status_via_uq_idx" ON "identity_verifiable_addresses" (nid, via, value); +CREATE INDEX IF NOT EXISTS "identity_verifiable_addresses_status_via_idx" ON "identity_verifiable_addresses" (nid, via, value); +CREATE INDEX IF NOT EXISTS identity_recovery_addresses_nid_id_idx ON identity_recovery_addresses (nid, id); diff --git a/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.up.sql b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.up.sql new file mode 100644 index 000000000000..dae62489b9e6 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000000_identity_verifiable_addresses_pk.sqlite.up.sql @@ -0,0 +1,30 @@ +CREATE TABLE IF NOT EXISTS "_identity_verifiable_addresses_tmp" ( +"id" TEXT NOT NULL, +"status" TEXT NOT NULL, +"via" TEXT NOT NULL, +"verified" bool NOT NULL, +"value" TEXT NOT NULL, +"verified_at" DATETIME, +"identity_id" TEXT NOT NULL, +"created_at" DATETIME NOT NULL, +"updated_at" DATETIME NOT NULL, +"nid" TEXT NOT NULL, +PRIMARY KEY ("identity_id","id"), +FOREIGN KEY ("identity_id") REFERENCES "identities" ("id") ON UPDATE RESTRICT ON DELETE CASCADE, +FOREIGN KEY ("nid") REFERENCES "networks" ("id") ON UPDATE RESTRICT ON DELETE CASCADE +); + +INSERT INTO "_identity_verifiable_addresses_tmp" + ("id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid") +SELECT + "id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid" +FROM "identity_verifiable_addresses"; + +DROP TABLE "identity_verifiable_addresses"; +ALTER TABLE "_identity_verifiable_addresses_tmp" RENAME TO "identity_verifiable_addresses"; + +CREATE UNIQUE INDEX "identity_verifiable_addresses_status_via_uq_idx" ON "identity_verifiable_addresses" (nid, via, value); +CREATE UNIQUE INDEX "identity_verifiable_addresses_id_uq_idx" ON "identity_verifiable_addresses" (id); +CREATE INDEX "identity_verifiable_addresses_status_via_idx" ON "identity_verifiable_addresses" (nid, via, value); +CREATE INDEX identity_verifiable_addresses_nid_id_idx ON identity_recovery_addresses (nid, id); +CREATE INDEX identity_verifiable_addresses_id_nid_idx ON identity_recovery_addresses (id, nid); diff --git a/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.down.sql b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.down.sql new file mode 100644 index 000000000000..50ed817bcf9c --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.down.sql @@ -0,0 +1,24 @@ +ALTER TABLE identity_recovery_codes + DROP FOREIGN KEY identity_recovery_codes_identity_recovery_addresses_id_fk, + DROP FOREIGN KEY identity_recovery_codes_identity_id_fk; + +ALTER TABLE identity_recovery_tokens + DROP FOREIGN KEY identity_recovery_tokens_identity_id_fk, + DROP FOREIGN KEY identity_recovery_tokens_identity_recovery_addresses_id_fk; + +ALTER TABLE identity_recovery_addresses + DROP FOREIGN KEY identity_recovery_addresses_ibfk_1; + +ALTER TABLE identity_recovery_addresses + DROP PRIMARY KEY, + ADD PRIMARY KEY (id), + ADD CONSTRAINT identity_recovery_addresses_ibfk_1 FOREIGN KEY (identity_id) REFERENCES identities(id) ON DELETE CASCADE; + +ALTER TABLE identity_recovery_codes + ADD CONSTRAINT identity_recovery_codes_identity_recovery_addresses_id_fk FOREIGN KEY (identity_recovery_address_id) REFERENCES identity_recovery_addresses (id) ON DELETE CASCADE, + ADD CONSTRAINT identity_recovery_codes_identity_id_fk FOREIGN KEY (identity_id) REFERENCES identities (id) ON DELETE CASCADE; + + +ALTER TABLE identity_recovery_tokens + ADD CONSTRAINT identity_recovery_tokens_ibfk_1 FOREIGN KEY (identity_recovery_address_id) REFERENCES identity_recovery_addresses(id) ON DELETE CASCADE, + ADD CONSTRAINT identity_recovery_tokens_identity_id_fk_idx FOREIGN KEY (identity_id) REFERENCES identities(id) ON DELETE CASCADE; diff --git a/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.up.sql b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.up.sql new file mode 100644 index 000000000000..c305120e3c93 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.mysql.up.sql @@ -0,0 +1,20 @@ +ALTER TABLE identity_recovery_codes + DROP FOREIGN KEY identity_recovery_codes_identity_recovery_addresses_id_fk, + DROP FOREIGN KEY identity_recovery_codes_identity_id_fk; + +ALTER TABLE identity_recovery_tokens + DROP FOREIGN KEY identity_recovery_tokens_ibfk_1, + DROP FOREIGN KEY identity_recovery_tokens_identity_id_fk_idx; + +ALTER TABLE identity_recovery_addresses + DROP PRIMARY KEY, + ADD PRIMARY KEY (identity_id, id), + ADD UNIQUE KEY identity_recovery_addresses_id_uq_idx (id); + +ALTER TABLE identity_recovery_codes + ADD CONSTRAINT identity_recovery_codes_identity_recovery_addresses_id_fk FOREIGN KEY (identity_recovery_address_id) REFERENCES identity_recovery_addresses (id) ON DELETE CASCADE, + ADD CONSTRAINT identity_recovery_codes_identity_id_fk FOREIGN KEY (identity_id) REFERENCES identities (id) ON DELETE CASCADE; + +ALTER TABLE identity_recovery_tokens + ADD CONSTRAINT identity_recovery_tokens_identity_recovery_addresses_id_fk FOREIGN KEY (identity_recovery_address_id) REFERENCES identity_recovery_addresses(id) ON DELETE CASCADE, + ADD CONSTRAINT identity_recovery_tokens_identity_id_fk FOREIGN KEY (identity_id) REFERENCES identities(id) ON DELETE CASCADE; diff --git a/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.down.sql b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.down.sql new file mode 100644 index 000000000000..4d0b140857a4 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE identity_recovery_addresses + DROP CONSTRAINT identity_recovery_addresses_pkey, + ADD PRIMARY KEY (id); diff --git a/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.up.sql b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.up.sql new file mode 100644 index 000000000000..859f0f1bd2c2 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.postgres.up.sql @@ -0,0 +1,17 @@ +CREATE UNIQUE INDEX identity_recovery_addresses_id_uq_idx ON identity_recovery_addresses (id); + +ALTER TABLE identity_recovery_codes + DROP CONSTRAINT identity_recovery_codes_identity_recovery_addresses_id_fk; + +ALTER TABLE identity_recovery_tokens + DROP CONSTRAINT identity_recovery_tokens_identity_recovery_address_id_fkey; + +ALTER TABLE identity_recovery_addresses + DROP CONSTRAINT identity_recovery_addresses_pkey, + ADD PRIMARY KEY (identity_id, id); + +ALTER TABLE identity_recovery_codes + ADD CONSTRAINT identity_recovery_codes_identity_recovery_addresses_id_fk FOREIGN KEY (identity_recovery_address_id) REFERENCES identity_recovery_addresses(id) ON DELETE CASCADE; + +ALTER TABLE identity_recovery_tokens + ADD CONSTRAINT identity_recovery_tokens_identity_recovery_address_id_fkey FOREIGN KEY (identity_recovery_address_id) REFERENCES identity_recovery_addresses(id) ON DELETE CASCADE; diff --git a/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.down.sql b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.down.sql new file mode 100644 index 000000000000..923af86dca4b --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.down.sql @@ -0,0 +1,25 @@ +CREATE TABLE "_identity_recovery_addresses_tmp" ( +"id" TEXT PRIMARY KEY, +"via" TEXT NOT NULL, +"value" TEXT NOT NULL, +"identity_id" char(36) NOT NULL, +"created_at" DATETIME NOT NULL, +"updated_at" DATETIME NOT NULL, +"nid" char(36), +FOREIGN KEY (identity_id) REFERENCES identities (id) ON UPDATE NO ACTION ON DELETE CASCADE +); + +INSERT INTO "_identity_recovery_addresses_tmp" + ("id", "via", "value", "identity_id", "created_at", "updated_at", "nid") +SELECT + "id", "via", "value", "identity_id", "created_at", "updated_at", "nid" +FROM "identity_recovery_addresses"; + +DROP TABLE "identity_recovery_addresses"; +ALTER TABLE "_identity_recovery_addresses_tmp" RENAME TO "identity_recovery_addresses"; + +CREATE INDEX identity_recovery_addresses_nid_id_idx ON identity_recovery_addresses (nid, id); +CREATE INDEX identity_recovery_addresses_id_nid_idx ON identity_recovery_addresses (id, nid); +CREATE UNIQUE INDEX "identity_recovery_addresses_id_uq_idx" ON "identity_recovery_addresses" (id); +CREATE UNIQUE INDEX "identity_recovery_addresses_status_via_uq_idx" ON "identity_recovery_addresses" (nid, via, value); +CREATE INDEX "identity_recovery_addresses_status_via_idx" ON "identity_recovery_addresses" (nid, via, value); diff --git a/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.up.sql b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.up.sql new file mode 100644 index 000000000000..154e25167585 --- /dev/null +++ b/persistence/sql/migrations/sql/20241001000000000001_identity_recovery_addresses_pk.sqlite.up.sql @@ -0,0 +1,26 @@ +CREATE TABLE "_identity_recovery_addresses_tmp" ( +"id" TEXT NOT NULL, +"via" TEXT NOT NULL, +"value" TEXT NOT NULL, +"identity_id" TEXT NOT NULL, +"created_at" DATETIME NOT NULL, +"updated_at" DATETIME NOT NULL, +"nid" TEXT NOT NULL, +PRIMARY KEY (identity_id,id), +FOREIGN KEY (identity_id) REFERENCES identities (id) ON UPDATE RESTRICT ON DELETE CASCADE, +FOREIGN KEY (nid) REFERENCES networks (id) ON UPDATE RESTRICT ON DELETE CASCADE +); + +INSERT INTO "_identity_recovery_addresses_tmp" + ("id", "via", "value", "identity_id", "created_at", "updated_at", "nid") +SELECT + "id", "via", "value", "identity_id", "created_at", "updated_at", "nid" +FROM "identity_recovery_addresses"; + +DROP TABLE "identity_recovery_addresses"; +ALTER TABLE "_identity_recovery_addresses_tmp" RENAME TO "identity_recovery_addresses"; + +CREATE INDEX identity_recovery_addresses_nid_id_idx ON identity_recovery_addresses (nid, id); +CREATE UNIQUE INDEX "identity_recovery_addresses_id_uq_idx" ON "identity_recovery_addresses" (id); +CREATE UNIQUE INDEX "identity_recovery_addresses_status_via_uq_idx" ON "identity_recovery_addresses" (nid, via, value); +CREATE INDEX "identity_recovery_addresses_status_via_idx" ON "identity_recovery_addresses" (nid, via, value); diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index 85bcdf7466c8..a8f989341f17 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -7,11 +7,11 @@ import ( "context" "embed" "io/fs" + "slices" "time" "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" - "github.com/laher/mergefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -20,10 +20,12 @@ import ( "github.com/ory/kratos/persistence" "github.com/ory/kratos/persistence/sql/devices" idpersistence "github.com/ory/kratos/persistence/sql/identity" + "github.com/ory/kratos/persistence/sql/migrations/gomigrations" "github.com/ory/kratos/schema" "github.com/ory/kratos/session" "github.com/ory/kratos/x" "github.com/ory/x/contextx" + "github.com/ory/x/fsx" "github.com/ory/x/networkx" "github.com/ory/x/otelx" "github.com/ory/x/popx" @@ -57,8 +59,9 @@ type ( ) type persisterOptions struct { - extraMigrations []fs.FS - disableLogging bool + extraMigrations []fs.FS + extraGoMigrations popx.Migrations + disableLogging bool } type persisterOption func(o *persisterOptions) @@ -69,6 +72,12 @@ func WithExtraMigrations(fss ...fs.FS) persisterOption { } } +func WithExtraGoMigrations(ms ...popx.Migration) persisterOption { + return func(o *persisterOptions) { + o.extraGoMigrations = ms + } +} + func WithDisabledLogging(v bool) persisterOption { return func(o *persisterOptions) { o.disableLogging = v @@ -85,15 +94,12 @@ func NewPersister(ctx context.Context, r persisterDependencies, c *pop.Connectio logger.Logrus().SetLevel(logrus.WarnLevel) } m, err := popx.NewMigrationBox( - mergefs.Merge( - append( - []fs.FS{ - migrations, networkx.Migrations, - }, - o.extraMigrations..., - )..., - ), + fsx.Merge(append([]fs.FS{migrations, networkx.Migrations}, o.extraMigrations...)...), popx.NewMigrator(c, logger, r.Tracer(ctx), 0), + popx.WithGoMigrations(slices.Concat( + gomigrations.ChangeAddressesPK, + o.extraGoMigrations, + )), ) if err != nil { return nil, err