diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 899ab5a036..25969473d2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,15 +1,27 @@ -### Definition of Ready +# Which Problems Are Solved -- [ ] I am happy with the code -- [ ] Short description of the feature/issue is added in the pr description -- [ ] PR is linked to the corresponding user story -- [ ] Acceptance criteria are met -- [ ] All open todos and follow ups are defined in a new ticket and justified -- [ ] Deviations from the acceptance criteria and design are agreed with the PO and documented. -- [ ] No debug or dead code -- [ ] My code has no repetitions -- [ ] Critical parts are tested automatically -- [ ] Where possible E2E tests are implemented -- [ ] Documentation/examples are up-to-date -- [ ] All non-functional requirements are met -- [ ] Functionality of the acceptance criteria is checked manually on the dev system. +Replace this example text with a concise list of problems that this PR solves. +For example: +- If the property XY is not given, the system crashes with a nil pointer exception. + +# How the Problems Are Solved + +Replace this example text with a concise list of changes that this PR introduces. +For example: +- Validates if property XY is given and throws an error if not + +# Additional Changes + +Replace this example text with a concise list of additional changes that this PR introduces, that are not directly solving the initial problem but are related. +For example: +- The docs explicitly describe that the property XY is mandatory +- Adds missing translations for validations. + +# Additional Context + +Replace this example with links to related issues, discussions, discord threads, or other sources with more context. +Use the Closing #issue syntax for issues that are resolved with this PR. +- Closes #123 +- Discussion #456 +- Follow-up for PR #789 +- https://discord.com/channels/123/456 \ No newline at end of file diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ee49ed33c9..6796658f6f 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -5,6 +5,7 @@ on: jobs: test: + timeout-minutes: 10 strategy: fail-fast: false matrix: diff --git a/.github/workflows/ready_for_review.yml b/.github/workflows/ready_for_review.yml new file mode 100644 index 0000000000..2ead263dc9 --- /dev/null +++ b/.github/workflows/ready_for_review.yml @@ -0,0 +1,31 @@ +on: + pull_request: + types: [opened] + +jobs: + comment: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: | + const content = `### Thanks for your contribution @${{ github.event.pull_request.user.login }}! 🎉 + + Please make sure you tick the following checkboxes before marking this Pull Request (PR) as ready for review: + + - [ ] I am happy with the code + - [ ] Documentations and examples are up-to-date + - [ ] Logical behavior changes are tested automatically + - [ ] No debug or dead code + - [ ] My code has no repetitions + - [ ] The PR title adheres to the [conventional commit format](https://www.conventionalcommits.org/en/v1.0.0/) + - [ ] The example texts in the PR description are replaced. + - [ ] If there are any open TODOs or follow-ups, they are described in issues and link to this PR + - [ ] If there are deviations from a user stories acceptance criteria or design, they are agreed upon with the PO and documented. + `; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: content + }) \ No newline at end of file diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index b8d7952be3..ae6b815037 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -14,16 +14,16 @@ Tracing: # for type 'otel' is used for standard [open telemetry](https://opentelemetry.io) # Fraction: 1.0 # Endpoint: 'otel.collector.endpoint' - # + # # type 'log' or '' disables tracing - # + # # for type 'google' # ProjectID: '' # Fraction: 1.0 Type: none # ZITADEL_TRACING_TYPE Fraction: 1.0 # ZITADEL_TRACING_FRACTION # The endpoint of the otel collector endpoint - Endpoint: '' #ZITADEL_TRACING_ENDPOINT + Endpoint: "" #ZITADEL_TRACING_ENDPOINT Telemetry: # As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints. @@ -200,7 +200,7 @@ AssetStorage: # The Projections section defines the behavior for the scheduled and synchronous events projections. Projections: - # The maximum duration a transaction remains open + # The maximum duration a transaction remains open # before it spots left folding additional events # and updates the table. TransactionDuration: 500ms # ZITADEL_PROJECTIONS_TRANSACTIONDURATION @@ -264,7 +264,7 @@ Auth: # See Projections.BulkLimit SearchLimit: 1000 # ZITADEL_AUTH_SEARCHLIMIT Spooler: - # See Projections.TransationDuration + # See Projections.TransationDuration TransactionDuration: 10s #ZITADEL_AUTH_SPOOLER_TRANSACTIONDURATION # See Projections.BulkLimit BulkLimit: 100 #ZITADEL_AUTH_SPOOLER_BULKLIMIT @@ -704,6 +704,9 @@ DefaultInstance: PrivacyLink: https://zitadel.com/docs/legal/privacy-policy # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_PRIVACYLINK HelpLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_HELPLINK SupportEmail: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_SUPPORTEMAIL + DocsLink: https://zitadel.com/docs # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_DOCSLINK + CustomLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_CUSTOMLINK + CustomLinkText: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_CUSTOMLINKTEXT NotificationPolicy: PasswordChange: true # ZITADEL_DEFAULTINSTANCE_NOTIFICATIONPOLICY_PASSWORDCHANGE LabelPolicy: @@ -1432,4 +1435,4 @@ InitProjections: Enabled: true # ZITADEL_INITPROJECTIONS_ENABLED RetryFailedAfter: 100ms # ZITADEL_INITPROJECTIONS_RETRYFAILEDAFTER MaxFailureCount: 2 # ZITADEL_INITPROJECTIONS_MAXFAILURECOUNT - BulkLimit: 1000 # ZITADEL_INITPROJECTIONS_BULKLIMIT \ No newline at end of file + BulkLimit: 1000 # ZITADEL_INITPROJECTIONS_BULKLIMIT diff --git a/cmd/initialise/init.go b/cmd/initialise/init.go index 7451f73ad3..d45bacfc17 100644 --- a/cmd/initialise/init.go +++ b/cmd/initialise/init.go @@ -19,6 +19,7 @@ var ( createUserStmt string grantStmt string + settingsStmt string databaseStmt string createEventstoreStmt string createProjectionsStmt string @@ -53,7 +54,7 @@ The user provided by flags needs privileges to }, } - cmd.AddCommand(newZitadel(), newDatabase(), newUser(), newGrant()) + cmd.AddCommand(newZitadel(), newDatabase(), newUser(), newGrant(), newSettings()) return cmd } @@ -62,6 +63,7 @@ func InitAll(ctx context.Context, config *Config) { VerifyUser(config.Database.Username(), config.Database.Password()), VerifyDatabase(config.Database.DatabaseName()), VerifyGrant(config.Database.DatabaseName(), config.Database.Username()), + VerifySettings(config.Database.DatabaseName(), config.Database.Username()), ) logging.OnError(err).Fatal("unable to initialize the database") @@ -147,6 +149,11 @@ func ReadStmts(typ string) (err error) { return err } + settingsStmt, err = readStmt(typ, "11_settings") + if err != nil { + return err + } + return nil } diff --git a/cmd/initialise/sql/cockroach/11_settings.sql b/cmd/initialise/sql/cockroach/11_settings.sql new file mode 100644 index 0000000000..5fa9dd72f6 --- /dev/null +++ b/cmd/initialise/sql/cockroach/11_settings.sql @@ -0,0 +1,4 @@ +-- replace the first %[1]q with the database in double quotes +-- replace the second \%[2]q with the user in double quotes$ +-- For more information see technical advisory 10009 (https://zitadel.com/docs/support/advisory/a10009) +ALTER ROLE %[2]q IN DATABASE %[1]q SET enable_durable_locking_for_serializable = on; \ No newline at end of file diff --git a/cmd/initialise/sql/postgres/11_settings.sql b/cmd/initialise/sql/postgres/11_settings.sql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cmd/initialise/verify_settings.go b/cmd/initialise/verify_settings.go new file mode 100644 index 0000000000..75e811663f --- /dev/null +++ b/cmd/initialise/verify_settings.go @@ -0,0 +1,44 @@ +package initialise + +import ( + _ "embed" + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/zitadel/logging" + + "github.com/zitadel/zitadel/internal/database" +) + +func newSettings() *cobra.Command { + return &cobra.Command{ + Use: "settings", + Short: "Ensures proper settings on the database", + Long: `Ensures proper settings on the database. + +Prerequisites: +- cockroachDB or postgreSQL + +Cockroach +- Sets enable_durable_locking_for_serializable to on for the zitadel user and database +`, + Run: func(cmd *cobra.Command, args []string) { + config := MustNewConfig(viper.GetViper()) + + err := initialise(config.Database, VerifySettings(config.Database.DatabaseName(), config.Database.Username())) + logging.OnError(err).Fatal("unable to set settings") + }, + } +} + +func VerifySettings(databaseName, username string) func(*database.DB) error { + return func(db *database.DB) error { + if db.Type() == "postgres" { + return nil + } + logging.WithFields("user", username, "database", databaseName).Info("verify settings") + + return exec(db, fmt.Sprintf(settingsStmt, databaseName, username), nil) + } +} diff --git a/cmd/setup/26.go b/cmd/setup/26.go new file mode 100644 index 0000000000..860198a75c --- /dev/null +++ b/cmd/setup/26.go @@ -0,0 +1,27 @@ +package setup + +import ( + "context" + _ "embed" + + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/eventstore" +) + +var ( + //go:embed 26.sql + authUsers3 string +) + +type AuthUsers3 struct { + dbClient *database.DB +} + +func (mig *AuthUsers3) Execute(ctx context.Context, _ eventstore.Event) error { + _, err := mig.dbClient.ExecContext(ctx, authUsers3) + return err +} + +func (mig *AuthUsers3) String() string { + return "26_auth_users3" +} diff --git a/cmd/setup/26.sql b/cmd/setup/26.sql new file mode 100644 index 0000000000..fa709d667d --- /dev/null +++ b/cmd/setup/26.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS auth.users3 ( + instance_id TEXT NOT NULL, + id TEXT NOT NULL, + resource_owner TEXT NOT NULL, + change_date TIMESTAMPTZ NULL, + password_set BOOL NULL, + password_change TIMESTAMPTZ NULL, + last_login TIMESTAMPTZ NULL, + init_required BOOL NULL, + mfa_init_skipped TIMESTAMPTZ NULL, + username_change_required BOOL NULL, + passwordless_init_required BOOL NULL, + password_init_required BOOL NULL, + + PRIMARY KEY (instance_id, id) +) diff --git a/cmd/setup/27.go b/cmd/setup/27.go new file mode 100644 index 0000000000..ee420ddfae --- /dev/null +++ b/cmd/setup/27.go @@ -0,0 +1,27 @@ +package setup + +import ( + "context" + _ "embed" + + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/eventstore" +) + +var ( + //go:embed 27.sql + addSAMLNameIDFormat string +) + +type IDPTemplate6SAMLNameIDFormat struct { + dbClient *database.DB +} + +func (mig *IDPTemplate6SAMLNameIDFormat) Execute(ctx context.Context, _ eventstore.Event) error { + _, err := mig.dbClient.ExecContext(ctx, addSAMLNameIDFormat) + return err +} + +func (mig *IDPTemplate6SAMLNameIDFormat) String() string { + return "26_idp_templates6_add_saml_name_id_format" +} diff --git a/cmd/setup/27.sql b/cmd/setup/27.sql new file mode 100644 index 0000000000..0e0503b7f1 --- /dev/null +++ b/cmd/setup/27.sql @@ -0,0 +1,2 @@ +ALTER TABLE IF EXISTS projections.idp_templates6_saml ADD COLUMN IF NOT EXISTS name_id_format SMALLINT; +ALTER TABLE IF EXISTS projections.idp_templates6_saml ADD COLUMN IF NOT EXISTS transient_mapping_attribute_name TEXT; diff --git a/cmd/setup/config.go b/cmd/setup/config.go index bb96e9912b..1ba85804ab 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -108,6 +108,8 @@ type Steps struct { s23CorrectGlobalUniqueConstraints *CorrectGlobalUniqueConstraints s24AddActorToAuthTokens *AddActorToAuthTokens s25User11AddLowerFieldsToVerifiedEmail *User11AddLowerFieldsToVerifiedEmail + s26AuthUsers3 *AuthUsers3 + s27IDPTemplate6SAMLNameIDFormat *IDPTemplate6SAMLNameIDFormat } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 693ec81e32..bb0111d5be 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -138,6 +138,8 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s23CorrectGlobalUniqueConstraints = &CorrectGlobalUniqueConstraints{dbClient: esPusherDBClient} steps.s24AddActorToAuthTokens = &AddActorToAuthTokens{dbClient: queryDBClient} steps.s25User11AddLowerFieldsToVerifiedEmail = &User11AddLowerFieldsToVerifiedEmail{dbClient: esPusherDBClient} + steps.s26AuthUsers3 = &AuthUsers3{dbClient: esPusherDBClient} + steps.s27IDPTemplate6SAMLNameIDFormat = &IDPTemplate6SAMLNameIDFormat{dbClient: esPusherDBClient} err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -175,6 +177,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s22ActiveInstancesIndex, steps.s23CorrectGlobalUniqueConstraints, steps.s24AddActorToAuthTokens, + steps.s26AuthUsers3, } { mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") } @@ -188,6 +191,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s18AddLowerFieldsToLoginNames, steps.s21AddBlockFieldToLimits, steps.s25User11AddLowerFieldsToVerifiedEmail, + steps.s27IDPTemplate6SAMLNameIDFormat, } { mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") } diff --git a/console/src/app/directives/scrollable/scrollable.directive.ts b/console/src/app/directives/scrollable/scrollable.directive.ts index 0ee83a6f8e..a8cda5fae6 100644 --- a/console/src/app/directives/scrollable/scrollable.directive.ts +++ b/console/src/app/directives/scrollable/scrollable.directive.ts @@ -1,6 +1,7 @@ import { Directive, ElementRef, EventEmitter, HostListener, Output } from '@angular/core'; @Directive({ + standalone: true, selector: '[cnslScrollable]', }) export class ScrollableDirective { @@ -15,7 +16,6 @@ export class ScrollableDirective { const top = event.target.scrollTop; const height = this.el.nativeElement.scrollHeight; const offset = this.el.nativeElement.offsetHeight; - // emit bottom event if (top > height - offset - 1) { this.scrollPosition.emit('bottom'); diff --git a/console/src/app/directives/scrollable/scrollable.module.ts b/console/src/app/directives/scrollable/scrollable.module.ts deleted file mode 100644 index 89bcbfabc1..0000000000 --- a/console/src/app/directives/scrollable/scrollable.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; - -import { ScrollableDirective } from './scrollable.directive'; - -@NgModule({ - declarations: [ScrollableDirective], - imports: [CommonModule], - exports: [ScrollableDirective], -}) -export class ScrollableModule {} diff --git a/console/src/app/modules/changes/changes.module.ts b/console/src/app/modules/changes/changes.module.ts index 9c087e6383..c19500ffa9 100644 --- a/console/src/app/modules/changes/changes.module.ts +++ b/console/src/app/modules/changes/changes.module.ts @@ -6,7 +6,6 @@ import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatTooltipModule } from '@angular/material/tooltip'; import { TranslateModule } from '@ngx-translate/core'; -import { ScrollableModule } from 'src/app/directives/scrollable/scrollable.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module'; import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module'; @@ -18,7 +17,6 @@ import { ChangesComponent } from './changes.component'; declarations: [ChangesComponent], imports: [ CommonModule, - ScrollableModule, MatProgressSpinnerModule, TranslateModule, MatIconModule, @@ -30,6 +28,6 @@ import { ChangesComponent } from './changes.component'; MatTooltipModule, AvatarModule, ], - exports: [ChangesComponent, ScrollableModule], + exports: [ChangesComponent], }) export class ChangesModule {} diff --git a/console/src/app/modules/footer/footer.component.html b/console/src/app/modules/footer/footer.component.html index fdf2924441..26d863d129 100644 --- a/console/src/app/modules/footer/footer.component.html +++ b/console/src/app/modules/footer/footer.component.html @@ -1,11 +1,11 @@