Merge branch 'main' into feat/10445-organization-apis-with-rel-tables

This commit is contained in:
Marco Ardizzone
2025-09-18 12:59:10 +02:00
9 changed files with 67 additions and 18 deletions

27
cmd/setup/65.go Normal file
View File

@@ -0,0 +1,27 @@
package setup
import (
"context"
_ "embed"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/eventstore"
)
var (
//go:embed 65.sql
userMetadata5Index string
)
type FixUserMetadata5Index struct {
dbClient *database.DB
}
func (mig *FixUserMetadata5Index) Execute(ctx context.Context, _ eventstore.Event) error {
_, err := mig.dbClient.ExecContext(ctx, userMetadata5Index)
return err
}
func (mig *FixUserMetadata5Index) String() string {
return "65_fix_user_metadata5_index"
}

3
cmd/setup/65.sql Normal file
View File

@@ -0,0 +1,3 @@
ALTER INDEX IF EXISTS projections.user_metadata5_metadata_key_idx
RENAME TO user_metadata5_key_idx;
DROP INDEX IF EXISTS projections.user_metadata5_metadata_value_idx;

View File

@@ -161,6 +161,7 @@ type Steps struct {
s62HTTPProviderAddSigningKey *HTTPProviderAddSigningKey
s63AlterResourceCounts *AlterResourceCounts
s64ChangePushPosition *ChangePushPosition
s65FixUserMetadata5Index *FixUserMetadata5Index
}
func MustNewSteps(v *viper.Viper) *Steps {

View File

@@ -222,6 +222,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s62HTTPProviderAddSigningKey = &HTTPProviderAddSigningKey{dbClient: dbClient}
steps.s63AlterResourceCounts = &AlterResourceCounts{dbClient: dbClient}
steps.s64ChangePushPosition = &ChangePushPosition{dbClient: dbClient}
steps.s65FixUserMetadata5Index = &FixUserMetadata5Index{dbClient: dbClient}
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
logging.OnError(err).Fatal("unable to start projections")
@@ -274,6 +275,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s62HTTPProviderAddSigningKey,
steps.s63AlterResourceCounts,
steps.s64ChangePushPosition,
steps.s65FixUserMetadata5Index,
} {
setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed")
if setupErr != nil {

View File

@@ -49,8 +49,8 @@ func (*userMetadataProjection) Init() *old_handler.Check {
},
handler.NewPrimaryKey(UserMetadataColumnInstanceID, UserMetadataColumnUserID, UserMetadataColumnKey),
handler.WithIndex(handler.NewIndex("resource_owner", []string{UserGrantResourceOwner})),
handler.WithIndex(handler.NewIndex("metadata_key", []string{UserMetadataColumnKey})),
handler.WithIndex(handler.NewIndex("metadata_value", []string{UserMetadataColumnValue})),
handler.WithIndex(handler.NewIndex("key", []string{UserMetadataColumnKey})),
handler.WithIndex(handler.NewIndex("value", []string{"sha256(" + UserMetadataColumnValue + ")"})),
),
)
}

View File

@@ -648,13 +648,12 @@ func (q *BytesQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
func (q *BytesQuery) comp() sq.Sqlizer {
switch q.Compare {
case BytesEquals:
return sq.Eq{q.Column.identifier(): q.Value}
return sq.Expr("sha256("+q.Column.identifier()+") = sha256(?)", q.Value)
case BytesNotEquals:
return sq.NotEq{q.Column.identifier(): q.Value}
return sq.Expr("sha256("+q.Column.identifier()+") <> sha256(?)", q.Value)
case bytesCompareMax:
return nil
}
return nil
}

View File

@@ -2287,7 +2287,7 @@ func TestBytesQuery_comp(t *testing.T) {
Compare: BytesEquals,
},
want: want{
query: sq.Eq{"test_table.test_col": []byte("foo")},
query: sq.Expr("sha256(test_table.test_col) = sha256(?)", []byte("foo")),
},
},
{
@@ -2298,7 +2298,7 @@ func TestBytesQuery_comp(t *testing.T) {
Compare: BytesNotEquals,
},
want: want{
query: sq.NotEq{"test_table.test_col": []byte("foo")},
query: sq.Expr("sha256(test_table.test_col) <> sha256(?)", []byte("foo")),
},
},
{
@@ -2322,7 +2322,7 @@ func TestBytesQuery_comp(t *testing.T) {
},
want: want{
err: true,
query: sq.Eq{"": []byte("foo")},
query: sq.Expr("sha256() = sha256(?)", []byte("foo")),
},
},
}

View File

@@ -634,7 +634,7 @@ func (q *Queries) searchUsers(ctx context.Context, queries *UserSearchQueries, p
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
query, scan := prepareUsersQuery()
query, scan := prepareUsersQuery(queries.SortingColumn)
query = userPermissionCheckV2(ctx, query, permissionCheckV2, queries.Queries)
stmt, args, err := queries.toQuery(query).Where(sq.Eq{
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
@@ -1270,7 +1270,7 @@ func prepareUserUniqueQuery() (sq.SelectBuilder, func(*sql.Row) (bool, error)) {
}
}
func prepareUsersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
func prepareUsersQuery(orderBy Column) (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
return sq.Select(
UserIDCol.identifier(),
UserCreationDateCol.identifier(),
@@ -1302,6 +1302,7 @@ func prepareUsersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
MachineDescriptionCol.identifier(),
MachineSecretCol.identifier(),
MachineAccessTokenTypeCol.identifier(),
orderBy.orderBy(),
countColumn.identifier()).
Distinct().
From(userTable.identifier()).
@@ -1319,6 +1320,7 @@ func prepareUsersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
preferredLoginName := sql.NullString{}
human, machine := sqlHuman{}, sqlMachine{}
var orderByValue any
err := rows.Scan(
&u.ID,
@@ -1354,6 +1356,7 @@ func prepareUsersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
&machine.encodedSecret,
&machine.accessTokenType,
&orderByValue,
&count,
)
if err != nil {

View File

@@ -9,6 +9,7 @@ import (
"regexp"
"testing"
sq "github.com/Masterminds/squirrel"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/text/language"
@@ -396,6 +397,7 @@ var (
` projections.users14_machines.description,` +
` projections.users14_machines.secret,` +
` projections.users14_machines.access_token_type,` +
` projections.users14.id,` +
` COUNT(*) OVER ()` +
` FROM projections.users14` +
` LEFT JOIN projections.users14_humans ON projections.users14.id = projections.users14_humans.user_id AND projections.users14.instance_id = projections.users14_humans.instance_id` +
@@ -435,6 +437,7 @@ var (
"description",
"secret",
"access_token_type",
"id",
"count",
}
countUsersQuery = "SELECT COUNT(*) OVER () FROM projections.users14"
@@ -944,8 +947,10 @@ func Test_UserPrepares(t *testing.T) {
object: (*NotifyUser)(nil),
},
{
name: "prepareUsersQuery no result",
prepare: prepareUsersQuery,
name: "prepareUsersQuery no result",
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
return prepareUsersQuery(UserIDCol)
},
want: want{
sqlExpectations: mockQuery(
regexp.QuoteMeta(usersQuery),
@@ -962,8 +967,10 @@ func Test_UserPrepares(t *testing.T) {
object: &Users{Users: []*User{}},
},
{
name: "prepareUsersQuery one result",
prepare: prepareUsersQuery,
name: "prepareUsersQuery one result",
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
return prepareUsersQuery(UserIDCol)
},
want: want{
sqlExpectations: mockQueries(
regexp.QuoteMeta(usersQuery),
@@ -1002,6 +1009,7 @@ func Test_UserPrepares(t *testing.T) {
nil,
nil,
nil,
"id", // orderBy col
},
},
),
@@ -1043,8 +1051,10 @@ func Test_UserPrepares(t *testing.T) {
},
},
{
name: "prepareUsersQuery multiple results",
prepare: prepareUsersQuery,
name: "prepareUsersQuery multiple results",
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
return prepareUsersQuery(UserIDCol)
},
want: want{
sqlExpectations: mockQueries(
regexp.QuoteMeta(usersQuery),
@@ -1083,6 +1093,7 @@ func Test_UserPrepares(t *testing.T) {
nil,
nil,
nil,
"id", // orderBy col
},
{
"id",
@@ -1117,6 +1128,7 @@ func Test_UserPrepares(t *testing.T) {
"description",
"secret",
domain.OIDCTokenTypeBearer,
"id", // orderBy col
},
},
),
@@ -1176,8 +1188,10 @@ func Test_UserPrepares(t *testing.T) {
},
},
{
name: "prepareUsersQuery sql err",
prepare: prepareUsersQuery,
name: "prepareUsersQuery sql err",
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) {
return prepareUsersQuery(UserIDCol)
},
want: want{
sqlExpectations: mockQueryErr(
regexp.QuoteMeta(usersQuery),