Skip to content

Commit 792cee3

Browse files
committed
feat: change primary key on identity_verifiable_addresses and identity_recovery_addresses
1 parent bafd32a commit 792cee3

19 files changed

+343
-58
lines changed

driver/registry.go

+33-29
Original file line numberDiff line numberDiff line change
@@ -7,45 +7,39 @@ import (
77
"context"
88
"io/fs"
99

10-
"github.com/ory/kratos/selfservice/sessiontokenexchange"
11-
"github.com/ory/x/contextx"
12-
"github.com/ory/x/jsonnetsecure"
13-
"github.com/ory/x/otelx"
14-
prometheus "github.com/ory/x/prometheusx"
15-
1610
"github.com/gorilla/sessions"
1711
"github.com/pkg/errors"
1812

19-
"github.com/ory/nosurf"
20-
21-
"github.com/ory/x/logrusx"
22-
13+
"github.com/ory/kratos/cipher"
2314
"github.com/ory/kratos/continuity"
2415
"github.com/ory/kratos/courier"
16+
"github.com/ory/kratos/driver/config"
2517
"github.com/ory/kratos/hash"
18+
"github.com/ory/kratos/identity"
19+
"github.com/ory/kratos/persistence"
2620
"github.com/ory/kratos/schema"
21+
"github.com/ory/kratos/selfservice/errorx"
22+
"github.com/ory/kratos/selfservice/flow/login"
23+
"github.com/ory/kratos/selfservice/flow/logout"
2724
"github.com/ory/kratos/selfservice/flow/recovery"
25+
"github.com/ory/kratos/selfservice/flow/registration"
2826
"github.com/ory/kratos/selfservice/flow/settings"
2927
"github.com/ory/kratos/selfservice/flow/verification"
28+
"github.com/ory/kratos/selfservice/sessiontokenexchange"
3029
"github.com/ory/kratos/selfservice/strategy/code"
3130
"github.com/ory/kratos/selfservice/strategy/link"
32-
33-
"github.com/ory/x/healthx"
34-
35-
"github.com/ory/kratos/persistence"
36-
"github.com/ory/kratos/selfservice/flow/login"
37-
"github.com/ory/kratos/selfservice/flow/logout"
38-
"github.com/ory/kratos/selfservice/flow/registration"
39-
40-
"github.com/ory/kratos/x"
41-
42-
"github.com/ory/x/dbal"
43-
44-
"github.com/ory/kratos/driver/config"
45-
"github.com/ory/kratos/identity"
46-
"github.com/ory/kratos/selfservice/errorx"
4731
password2 "github.com/ory/kratos/selfservice/strategy/password"
4832
"github.com/ory/kratos/session"
33+
"github.com/ory/kratos/x"
34+
"github.com/ory/nosurf"
35+
"github.com/ory/x/contextx"
36+
"github.com/ory/x/dbal"
37+
"github.com/ory/x/healthx"
38+
"github.com/ory/x/jsonnetsecure"
39+
"github.com/ory/x/logrusx"
40+
"github.com/ory/x/otelx"
41+
"github.com/ory/x/popx"
42+
prometheus "github.com/ory/x/prometheusx"
4943
)
5044

5145
type Registry interface {
@@ -85,6 +79,8 @@ type Registry interface {
8579
continuity.ManagementProvider
8680
continuity.PersistenceProvider
8781

82+
cipher.Provider
83+
8884
courier.Provider
8985

9086
persistence.Provider
@@ -186,10 +182,12 @@ type options struct {
186182
replaceIdentitySchemaProvider func(Registry) schema.IdentitySchemaProvider
187183
inspect func(Registry) error
188184
extraMigrations []fs.FS
189-
replacementStrategies []NewStrategy
190-
extraHooks map[string]func(config.SelfServiceHook) any
191-
disableMigrationLogging bool
192-
jsonnetPool jsonnetsecure.Pool
185+
extraGoMigrations popx.Migrations
186+
187+
replacementStrategies []NewStrategy
188+
extraHooks map[string]func(config.SelfServiceHook) any
189+
disableMigrationLogging bool
190+
jsonnetPool jsonnetsecure.Pool
193191
}
194192

195193
type RegistryOption func(*options)
@@ -251,6 +249,12 @@ func WithExtraMigrations(m ...fs.FS) RegistryOption {
251249
}
252250
}
253251

252+
func WithExtraGoMigrations(m ...popx.Migration) RegistryOption {
253+
return func(o *options) {
254+
o.extraGoMigrations = append(o.extraGoMigrations, m...)
255+
}
256+
}
257+
254258
func WithDisabledMigrationLogging() RegistryOption {
255259
return func(o *options) {
256260
o.disableMigrationLogging = true

driver/registry_default.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,10 @@ func (m *RegistryDefault) Init(ctx context.Context, ctxer contextx.Contextualize
672672
m.Logger().WithError(err).Warnf("Unable to open database, retrying.")
673673
return errors.WithStack(err)
674674
}
675-
p, err := sql.NewPersister(ctx, m, c, sql.WithExtraMigrations(o.extraMigrations...), sql.WithDisabledLogging(o.disableMigrationLogging))
675+
p, err := sql.NewPersister(ctx, m, c,
676+
sql.WithExtraMigrations(o.extraMigrations...),
677+
sql.WithExtraGoMigrations(o.extraGoMigrations...),
678+
sql.WithDisabledLogging(o.disableMigrationLogging))
676679
if err != nil {
677680
m.Logger().WithError(err).Warnf("Unable to initialize persister, retrying.")
678681
return err

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ require (
5353
github.com/jmoiron/sqlx v1.4.0
5454
github.com/julienschmidt/httprouter v1.3.0
5555
github.com/knadh/koanf/parsers/json v0.1.0
56-
github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7
56+
github.com/laher/mergefs v0.1.2-0.20230223191438-d16611b2f4e7 // indirect
5757
github.com/lestrrat-go/jwx/v2 v2.1.1
5858
github.com/luna-duclos/instrumentedsql v1.1.3
5959
github.com/mailhog/MailHog v1.0.1

go.sum

-1
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,6 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
551551
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
552552
github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno=
553553
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
554-
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
555554
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
556555
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
557556
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=

persistence/sql/migratest/migration_test.go

+14-15
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,21 @@ import (
88
"encoding/json"
99
"os"
1010
"path/filepath"
11+
"slices"
1112
"sync"
1213
"testing"
1314
"time"
1415

15-
"github.com/ory/x/pagination/keysetpagination"
16-
"github.com/ory/x/servicelocatorx"
17-
18-
"github.com/ory/kratos/identity"
19-
2016
"github.com/bradleyjkemp/cupaloy/v2"
21-
"github.com/stretchr/testify/assert"
22-
23-
"github.com/ory/x/dbal"
24-
25-
"github.com/ory/kratos/x/xsql"
26-
27-
"github.com/ory/x/migratest"
28-
2917
"github.com/gobuffalo/pop/v6"
3018
"github.com/sirupsen/logrus"
19+
"github.com/stretchr/testify/assert"
3120
"github.com/stretchr/testify/require"
3221

3322
"github.com/ory/kratos/driver"
3423
"github.com/ory/kratos/driver/config"
24+
"github.com/ory/kratos/identity"
25+
"github.com/ory/kratos/persistence/sql/migrations/gomigrations"
3526
"github.com/ory/kratos/selfservice/flow/login"
3627
"github.com/ory/kratos/selfservice/flow/recovery"
3728
"github.com/ory/kratos/selfservice/flow/registration"
@@ -41,9 +32,14 @@ import (
4132
"github.com/ory/kratos/selfservice/strategy/link"
4233
"github.com/ory/kratos/session"
4334
"github.com/ory/kratos/x"
35+
"github.com/ory/kratos/x/xsql"
4436
"github.com/ory/x/configx"
37+
"github.com/ory/x/dbal"
4538
"github.com/ory/x/logrusx"
39+
"github.com/ory/x/migratest"
40+
"github.com/ory/x/pagination/keysetpagination"
4641
"github.com/ory/x/popx"
42+
"github.com/ory/x/servicelocatorx"
4743
"github.com/ory/x/sqlcon"
4844
"github.com/ory/x/sqlcon/dockertest"
4945
)
@@ -87,15 +83,15 @@ func TestMigrations_Postgres(t *testing.T) {
8783
t.Skip("skipping testing in short mode")
8884
}
8985
t.Parallel()
90-
testDatabase(t, "postgres", dockertest.ConnectPop(t, dockertest.RunTestPostgreSQLWithVersion(t, "11.8")))
86+
testDatabase(t, "postgres", dockertest.ConnectPop(t, dockertest.RunTestPostgreSQLWithVersion(t, "14")))
9187
}
9288

9389
func TestMigrations_Mysql(t *testing.T) {
9490
if testing.Short() {
9591
t.Skip("skipping testing in short mode")
9692
}
9793
t.Parallel()
98-
testDatabase(t, "mysql", dockertest.ConnectPop(t, dockertest.RunTestMySQLWithVersion(t, "8.0.34")))
94+
testDatabase(t, "mysql", dockertest.ConnectPop(t, dockertest.RunTestMySQLWithVersion(t, "8.0")))
9995
}
10096

10197
func TestMigrations_Cockroach(t *testing.T) {
@@ -134,6 +130,9 @@ func testDatabase(t *testing.T, db string, c *pop.Connection) {
134130
os.DirFS("../migrations/sql"),
135131
popx.NewMigrator(c, l, nil, 1*time.Minute),
136132
popx.WithTestdata(t, os.DirFS("./testdata")),
133+
popx.WithGoMigrations(slices.Concat(
134+
gomigrations.ChangeAddressesPK,
135+
)),
137136
)
138137
require.NoError(t, err)
139138
tm.DumpMigrations = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright © 2024 Ory Corp
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package gomigrations
5+
6+
import (
7+
"fmt"
8+
"path/filepath"
9+
"runtime"
10+
11+
"github.com/gobuffalo/pop/v6"
12+
"github.com/pkg/errors"
13+
14+
"github.com/ory/x/popx"
15+
)
16+
17+
func path() string {
18+
_, file, line, _ := runtime.Caller(1)
19+
return fmt.Sprintf("%s:%d", filepath.Base(file), line)
20+
}
21+
22+
var ChangeAddressesPK = []popx.Migration{
23+
{
24+
Version: "20241001000000000000",
25+
Path: path(),
26+
Name: "Change primary key for identity_verifiable_addresses",
27+
Direction: "up",
28+
Type: "go",
29+
DBType: "cockroach",
30+
RunnerNoTx: func(m popx.Migration, c *pop.Connection) error {
31+
_, err := c.Store.Exec("ALTER TABLE identity_verifiable_addresses ALTER PRIMARY KEY USING COLUMNS (identity_id,id)")
32+
return errors.WithStack(err)
33+
},
34+
},
35+
{
36+
Version: "20241001000000000000",
37+
Path: path(),
38+
Name: "Revert primary key for identity_verifiable_addresses",
39+
Direction: "down",
40+
Type: "go",
41+
DBType: "cockroach",
42+
RunnerNoTx: func(m popx.Migration, c *pop.Connection) error {
43+
_, err := c.Store.Exec("ALTER TABLE identity_verifiable_addresses ALTER PRIMARY KEY USING COLUMNS (id)")
44+
return errors.WithStack(err)
45+
},
46+
},
47+
{
48+
Version: "20241001000000000001",
49+
Path: path(),
50+
Name: "Change primary key for identity_recovery_addresses",
51+
Direction: "up",
52+
Type: "go",
53+
DBType: "cockroach",
54+
RunnerNoTx: func(m popx.Migration, c *pop.Connection) error {
55+
_, err := c.Store.Exec("ALTER TABLE identity_recovery_addresses ALTER PRIMARY KEY USING COLUMNS (identity_id,id)")
56+
return errors.WithStack(err)
57+
},
58+
},
59+
{
60+
Version: "20241001000000000001",
61+
Path: path(),
62+
Name: "Revert primary key for identity_recovery_addresses",
63+
Direction: "down",
64+
Type: "go",
65+
DBType: "cockroach",
66+
RunnerNoTx: func(m popx.Migration, c *pop.Connection) error {
67+
_, err := c.Store.Exec("ALTER TABLE identity_recovery_addresses ALTER PRIMARY KEY USING COLUMNS (id)")
68+
return errors.WithStack(err)
69+
},
70+
},
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ALTER TABLE identity_verifiable_addresses
2+
DROP FOREIGN KEY identity_verifiable_addresses_ibfk_1;
3+
4+
ALTER TABLE identity_verifiable_addresses
5+
DROP PRIMARY KEY,
6+
ADD PRIMARY KEY (id),
7+
ADD CONSTRAINT identity_verifiable_addresses_ibfk_1 FOREIGN KEY (identity_id) REFERENCES identities(id) ON DELETE CASCADE;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ALTER TABLE identity_verifiable_addresses
2+
DROP PRIMARY KEY,
3+
ADD PRIMARY KEY (identity_id, id),
4+
ADD UNIQUE KEY identity_verifiable_addresses_id_uq_idx (id);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE identity_verifiable_addresses
2+
DROP CONSTRAINT identity_verifiable_addresses_pkey,
3+
ADD PRIMARY KEY (id);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CREATE UNIQUE INDEX identity_verifiable_addresses_id_uq_idx ON identity_verifiable_addresses (id);
2+
3+
ALTER TABLE identity_verification_codes
4+
DROP CONSTRAINT identity_verification_codes_identity_verifiable_addresses_id_fk;
5+
6+
ALTER TABLE identity_verification_tokens
7+
DROP CONSTRAINT identity_verification_tokens_identity_verifiable_address_i_fkey;
8+
9+
ALTER TABLE identity_verifiable_addresses
10+
DROP CONSTRAINT identity_verifiable_addresses_pkey,
11+
ADD PRIMARY KEY (identity_id, id);
12+
13+
ALTER TABLE identity_verification_codes
14+
ADD CONSTRAINT identity_verification_codes_identity_verifiable_addresses_id_fk FOREIGN KEY (identity_verifiable_address_id) REFERENCES identity_verifiable_addresses(id) ON DELETE CASCADE;
15+
16+
ALTER TABLE identity_verification_tokens
17+
ADD CONSTRAINT identity_verification_tokens_identity_verifiable_address_i_fkey FOREIGN KEY (identity_verifiable_address_id) REFERENCES identity_verifiable_addresses(id) ON DELETE CASCADE;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
CREATE TABLE IF NOT EXISTS "_identity_verifiable_addresses_tmp" (
2+
"id" TEXT PRIMARY KEY,
3+
"status" TEXT NOT NULL,
4+
"via" TEXT NOT NULL,
5+
"verified" bool NOT NULL,
6+
"value" TEXT NOT NULL,
7+
"verified_at" DATETIME,
8+
"identity_id" TEXT NOT NULL,
9+
"created_at" DATETIME NOT NULL,
10+
"updated_at" DATETIME NOT NULL,
11+
"nid" TEXT NOT NULL,
12+
FOREIGN KEY ("identity_id") REFERENCES "identities" ("id") ON UPDATE RESTRICT ON DELETE CASCADE,
13+
FOREIGN KEY ("nid") REFERENCES "networks" ("id") ON UPDATE RESTRICT ON DELETE CASCADE
14+
);
15+
16+
INSERT INTO "_identity_verifiable_addresses_tmp"
17+
("id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid")
18+
SELECT
19+
"id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid"
20+
FROM "identity_verifiable_addresses";
21+
22+
DROP TABLE "identity_verifiable_addresses";
23+
ALTER TABLE "_identity_verifiable_addresses_tmp" RENAME TO "identity_verifiable_addresses";
24+
25+
CREATE UNIQUE INDEX IF NOT EXISTS "identity_verifiable_addresses_status_via_uq_idx" ON "identity_verifiable_addresses" (nid, via, value);
26+
CREATE INDEX IF NOT EXISTS "identity_verifiable_addresses_status_via_idx" ON "identity_verifiable_addresses" (nid, via, value);
27+
CREATE INDEX IF NOT EXISTS identity_recovery_addresses_nid_id_idx ON identity_recovery_addresses (nid, id);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
CREATE TABLE IF NOT EXISTS "_identity_verifiable_addresses_tmp" (
2+
"id" TEXT NOT NULL,
3+
"status" TEXT NOT NULL,
4+
"via" TEXT NOT NULL,
5+
"verified" bool NOT NULL,
6+
"value" TEXT NOT NULL,
7+
"verified_at" DATETIME,
8+
"identity_id" TEXT NOT NULL,
9+
"created_at" DATETIME NOT NULL,
10+
"updated_at" DATETIME NOT NULL,
11+
"nid" TEXT NOT NULL,
12+
PRIMARY KEY ("identity_id","id"),
13+
FOREIGN KEY ("identity_id") REFERENCES "identities" ("id") ON UPDATE RESTRICT ON DELETE CASCADE,
14+
FOREIGN KEY ("nid") REFERENCES "networks" ("id") ON UPDATE RESTRICT ON DELETE CASCADE
15+
);
16+
17+
INSERT INTO "_identity_verifiable_addresses_tmp"
18+
("id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid")
19+
SELECT
20+
"id", "status", "via", "verified", "value", "verified_at", "identity_id", "created_at", "updated_at", "nid"
21+
FROM "identity_verifiable_addresses";
22+
23+
DROP TABLE "identity_verifiable_addresses";
24+
ALTER TABLE "_identity_verifiable_addresses_tmp" RENAME TO "identity_verifiable_addresses";
25+
26+
CREATE UNIQUE INDEX "identity_verifiable_addresses_status_via_uq_idx" ON "identity_verifiable_addresses" (nid, via, value);
27+
CREATE UNIQUE INDEX "identity_verifiable_addresses_id_uq_idx" ON "identity_verifiable_addresses" (id);
28+
CREATE INDEX "identity_verifiable_addresses_status_via_idx" ON "identity_verifiable_addresses" (nid, via, value);
29+
CREATE INDEX identity_verifiable_addresses_nid_id_idx ON identity_recovery_addresses (nid, id);
30+
CREATE INDEX identity_verifiable_addresses_id_nid_idx ON identity_recovery_addresses (id, nid);

0 commit comments

Comments
 (0)