diff --git a/cmd/e2e-setup/config.go b/cmd/e2e-setup/config.go new file mode 100644 index 0000000000..1a6bbac218 --- /dev/null +++ b/cmd/e2e-setup/config.go @@ -0,0 +1,118 @@ +package main + +import ( + "errors" + "fmt" + "regexp" + + "github.com/zitadel/zitadel/internal/id" + + "github.com/zitadel/zitadel/internal/database" + + internal_authz "github.com/zitadel/zitadel/internal/api/authz" + + static_config "github.com/zitadel/zitadel/internal/static/config" + + "github.com/zitadel/zitadel/internal/config/systemdefaults" + + "github.com/mitchellh/mapstructure" + "github.com/spf13/viper" + "github.com/zitadel/logging" + "github.com/zitadel/zitadel/internal/config/hook" +) + +type Config struct { + E2E *E2EConfig + Log *logging.Config + ExternalPort uint16 + ExternalDomain string + ExternalSecure bool + Database database.Config + AssetStorage static_config.AssetStorageConfig + WebAuthNName string + InternalAuthZ internal_authz.Config + Machine *id.Config + SystemDefaults systemdefaults.SystemDefaults +} + +func (c Config) Validate() error { + if c.E2E == nil { + return errors.New("no e2e config found") + } + return c.E2E.Validate() +} + +type E2EConfig struct { + Org string + MachineKeyPath string + ZitadelProjectResourceID string + APIURL string + IssuerURL string + Audience string + OrgOwnerPassword string + OrgOwnerViewerPassword string + OrgProjectCreatorPassword string + PasswordComplexityUserPassword string + LoginPolicyUserPassword string +} + +func (e E2EConfig) Validate() (err error) { + if e.Org == "" { + return errors.New("field Org is empty") + } + if e.MachineKeyPath == "" { + return errors.New("field MachineKeyPath is empty") + } + if e.ZitadelProjectResourceID == "" { + return errors.New("field ZitadelProjectResourceID is empty") + } + + audPattern := "number-[0-9]{17}" + matched, err := regexp.MatchString("number-[0-9]{17}", e.ZitadelProjectResourceID) + if err != nil { + return fmt.Errorf("validating ZitadelProjectResourceID failed: %w", err) + } + if !matched { + return fmt.Errorf("ZitadelProjectResourceID doesn't match regular expression %s", audPattern) + } + + if e.APIURL == "" { + return errors.New("field APIURL is empty") + } + if e.IssuerURL == "" { + return errors.New("field IssuerURL is empty") + } + if e.OrgOwnerPassword == "" { + return errors.New("field OrgOwnerPassword is empty") + } + if e.OrgOwnerViewerPassword == "" { + return errors.New("field OrgOwnerViewerPassword is empty") + } + if e.OrgProjectCreatorPassword == "" { + return errors.New("field OrgProjectCreatorPassword is empty") + } + if e.PasswordComplexityUserPassword == "" { + return errors.New("field PasswordComplexityUserPassword is empty") + } + if e.LoginPolicyUserPassword == "" { + return errors.New("field LoginPolicyUserPassword is empty") + } + return nil +} + +func MustNewConfig(v *viper.Viper) *Config { + config := new(Config) + + err := v.Unmarshal(config, + viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( + hook.Base64ToBytesHookFunc(), + hook.TagToLanguageHookFunc(), + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + )), + ) + err = config.Log.SetLogger() + logging.OnError(err).Fatal("unable to set logger") + + return config +} diff --git a/cmd/e2e-setup/consistency.go b/cmd/e2e-setup/consistency.go new file mode 100644 index 0000000000..47acbe630c --- /dev/null +++ b/cmd/e2e-setup/consistency.go @@ -0,0 +1,65 @@ +package main + +import ( + "context" + "fmt" + "time" + + "github.com/zitadel/logging" +) + +func awaitConsistency(ctx context.Context, cfg E2EConfig, expectUsers []userData) (err error) { + + retry := make(chan struct{}) + go func() { + // trigger first check + retry <- struct{}{} + }() + for { + select { + case <-retry: + err = checkCondition(ctx, cfg, expectUsers) + if err == nil { + logging.Log("AWAIT-QIOOJ").Info("setup is consistent") + return nil + } + logging.Log("AWAIT-VRk3Y").Info("setup is not consistent yet, retrying in a second: ", err) + time.Sleep(time.Second) + go func() { + retry <- struct{}{} + }() + case <-ctx.Done(): + return fmt.Errorf("setup failed to come to a consistent state: %s: %w", ctx.Err(), err) + } + } +} + +func checkCondition(ctx context.Context, cfg E2EConfig, expectUsers []userData) error { + token, err := newToken(cfg) + if err != nil { + return err + } + + foundUsers, err := listUsers(ctx, cfg.APIURL, token) + if err != nil { + return err + } + + var awaitingUsers []string +expectLoop: + for i := range expectUsers { + expectUser := expectUsers[i] + for j := range foundUsers { + foundUser := foundUsers[j] + if expectUser.desc+"_user_name" == foundUser { + continue expectLoop + } + } + awaitingUsers = append(awaitingUsers, expectUser.desc) + } + + if len(awaitingUsers) > 0 { + return fmt.Errorf("users %v are not consistent yet", awaitingUsers) + } + return nil +} diff --git a/cmd/e2e-setup/execute.go b/cmd/e2e-setup/execute.go new file mode 100644 index 0000000000..6febec706f --- /dev/null +++ b/cmd/e2e-setup/execute.go @@ -0,0 +1,110 @@ +package main + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "time" + + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/eventstore/v1/models" +) + +func execute(ctx context.Context, cmd *command.Commands, cfg E2EConfig, users []userData) error { + + orgOwner := newHuman(users[0]) + + orgOwnerID, org, err := cmd.SetUpOrg(ctx, &command.OrgSetup{ + Name: cfg.Org, + CustomDomain: "localhost", + Human: *orgOwner, + }) + if err != nil { + return err + } + + // Avoids the MFA nudge + if _, err = cmd.AddLoginPolicy(ctx, org.ResourceOwner, &domain.LoginPolicy{ + AllowUsernamePassword: true, + }); err != nil { + return err + } + + // Avoids the change password screen + if _, err = cmd.ChangePassword(ctx, org.ResourceOwner, orgOwnerID, cfg.OrgOwnerPassword, cfg.OrgOwnerPassword, ""); err != nil { + return err + } + + sa, err := cmd.AddMachine(ctx, org.ResourceOwner, &domain.Machine{ + Username: "e2e", + Name: "e2e", + Description: "User who calls the ZITADEL API for preparing end-to-end tests", + }) + if err != nil { + return err + } + + if _, err = cmd.AddOrgMember(ctx, org.ResourceOwner, sa.AggregateID, domain.RoleOrgOwner); err != nil { + return err + } + + key, err := cmd.AddUserMachineKey(ctx, &domain.MachineKey{ + ObjectRoot: models.ObjectRoot{ + AggregateID: sa.AggregateID, + }, + ExpirationDate: time.Now().Add(30 * 24 * time.Hour), + Type: domain.AuthNKeyTypeJSON, + }, org.ResourceOwner) + if err != nil { + return err + } + + json, err := key.MarshalJSON() + if err != nil { + return err + } + + if err = os.MkdirAll(filepath.Dir(cfg.MachineKeyPath), 0700); err != nil { + return err + } + + if err = ioutil.WriteFile(cfg.MachineKeyPath, json, 0600); err != nil { + return err + } + + for idx := range users[1:] { + user := users[idx] + + createdHuman, err := cmd.AddHuman(ctx, org.ResourceOwner, newHuman(user)) + if err != nil { + return err + } + + // Avoids the change password screen + if _, err = cmd.ChangePassword(ctx, org.ResourceOwner, createdHuman.ID, user.pw, user.pw, ""); err != nil { + return err + } + + if user.role != "" { + if _, err = cmd.AddOrgMember(ctx, org.ResourceOwner, createdHuman.ID, user.role); err != nil { + return err + } + } + } + return nil +} + +func newHuman(u userData) *command.AddHuman { + return &command.AddHuman{ + Username: u.desc + "_user_name", + FirstName: u.desc + "_first_name", + LastName: u.desc + "_last_name", + Password: u.pw, + Email: command.Email{ + Address: u.desc + ".e2e@zitadel.com", + Verified: true, + }, + } +} diff --git a/cmd/e2e-setup/main.go b/cmd/e2e-setup/main.go new file mode 100644 index 0000000000..b38e785a0b --- /dev/null +++ b/cmd/e2e-setup/main.go @@ -0,0 +1,139 @@ +package main + +import ( + "context" + _ "embed" + "flag" + "fmt" + "time" + + "github.com/zitadel/zitadel/internal/id" + + "github.com/spf13/viper" + + "github.com/zitadel/zitadel/internal/config/options" + + "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/webauthn" + + "gopkg.in/yaml.v3" + + "github.com/zitadel/zitadel/internal/domain" + + "github.com/zitadel/logging" +) + +type userData struct { + desc, role, pw string +} + +func main() { + // masterkey := flag.String("materkey", "MasterkeyNeedsToHave32Characters", "the ZITADEL installations masterkey") + debug := flag.Bool("debug", false, "print information that is helpful for debugging") + + err := options.InitViper() + logging.OnError(err).Fatalf("unable to initialize config: %s", err) + + flag.Parse() + viper. + fmt.Println(x) + conf := MustNewConfig(viper.GetViper()) + + if *debug { + printConfig("config", conf) + } + + logging.New().OnError(err).Fatal("validating e2e config failed") + + startE2ESetup(conf) +} + +func startE2ESetup(conf *Config /*, masterkey string*/) { + + id.Configure(conf.Machine) + + ctx := context.Background() + + dbClient, err := database.Connect(conf.Database) + logging.New().OnError(err).Fatalf("cannot start client for projection: %s", err) + + /* + keyStorage, err := cryptoDB.NewKeyStorage(dbClient, masterkey) + logging.New().OnError(err).Fatalf("cannot start key storage: %s", err) + + keys, err := ensureEncryptionKeys(conf.EncryptionKeys, keyStorage) + logging.New().OnError(err).Fatalf("failed ensuring encryption keys: %s", err) + */ + + eventstoreClient, err := eventstore.Start(dbClient) + logging.New().OnError(err).Fatalf("cannot start eventstore for queries: %s", err) + + storage, err := conf.AssetStorage.NewStorage(dbClient) + logging.New().OnError(err).Fatalf("cannot start asset storage client: %s", err) + + webAuthNConfig := &webauthn.Config{ + DisplayName: conf.WebAuthNName, + ExternalSecure: conf.ExternalSecure, + } + + commands, err := command.StartCommands( + eventstoreClient, + conf.SystemDefaults, + conf.InternalAuthZ.RolePermissionMappings, + storage, + webAuthNConfig, + conf.ExternalDomain, + conf.ExternalSecure, + conf.ExternalPort, + nil, //keys.IDPConfig, + nil, //keys.OTP, + nil, //keys.SMTP, + nil, //keys.SMS, + nil, //keys.User, + nil, //keys.DomainVerification, + nil, //keys.OIDC, + ) + logging.New().OnError(err).Errorf("cannot start commands: %s", err) + + users := []userData{{ + desc: "org_owner", + pw: conf.E2E.OrgOwnerPassword, + role: domain.RoleOrgOwner, + }, { + desc: "org_owner_viewer", + pw: conf.E2E.OrgOwnerViewerPassword, + role: domain.RoleOrgOwner, + }, { + desc: "org_project_creator", + pw: conf.E2E.OrgProjectCreatorPassword, + role: domain.RoleOrgProjectCreator, + }, { + desc: "login_policy_user", + pw: conf.E2E.LoginPolicyUserPassword, + }, { + desc: "password_complexity_user", + pw: conf.E2E.PasswordComplexityUserPassword, + }} + + err = execute(ctx, commands, *conf.E2E, users) + logging.New().OnError(err).Errorf("failed to execute commands steps") + + eventualConsistencyCtx, cancel := context.WithTimeout(ctx, 5*time.Minute) + defer cancel() + err = awaitConsistency( + eventualConsistencyCtx, + *conf.E2E, + users, + ) + logging.New().OnError(err).Fatal("failed to await consistency") +} + +func printConfig(desc string, cfg interface{}) { + bytes, err := yaml.Marshal(cfg) + logging.New().OnError(err).Fatal("cannot marshal config") + + logging.New().Info("got the following ", desc, " config") + fmt.Println(string(bytes)) +} diff --git a/cmd/e2e-setup/token.go b/cmd/e2e-setup/token.go new file mode 100644 index 0000000000..124ba0d416 --- /dev/null +++ b/cmd/e2e-setup/token.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/golang-jwt/jwt/v4" + "io/ioutil" + "net/http" + "os" + "strings" + "time" +) + +func newToken(cfg E2EConfig) (string, error) { + + keyBytes, err := os.ReadFile(cfg.MachineKeyPath) + if err != nil { + return "", err + } + + key := struct{ UserId, KeyId, Key string }{} + if err := json.Unmarshal(keyBytes, &key); err != nil { + return "", err + } + + if key.KeyId == "" || + key.UserId == "" || + key.Key == "" { + return "", fmt.Errorf("key is incomplete: %+v", key) + } + + now := time.Now() + iat := now.Unix() + exp := now.Add(55 * time.Minute).Unix() + + audience := cfg.Audience + if audience == "" { + audience = cfg.IssuerURL + } + + token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ + "iss": key.UserId, + "sub": key.UserId, + "aud": audience, + "iat": iat, + "exp": exp, + }) + + token.Header["alg"] = "RS256" + token.Header["kid"] = key.KeyId + + rsaKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(key.Key)) + if err != nil { + return "", err + } + + tokenString, err := token.SignedString(rsaKey) + if err != nil { + return "", err + } + + resp, err := http.PostForm(fmt.Sprintf("%s/oauth/v2/token", cfg.APIURL), map[string][]string{ + "grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, + "scope": {fmt.Sprintf("openid urn:zitadel:iam:org:project:id:%s:aud", strings.TrimPrefix(cfg.ZitadelProjectResourceID, "bignumber-"))}, + "assertion": {tokenString}, + }) + if err != nil { + return "", err + } + + tokenBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + if resp.StatusCode < 200 || resp.StatusCode > 399 { + return "", fmt.Errorf("getting token returned status code %d and body %s", resp.StatusCode, string(tokenBody)) + } + + tokenResp := struct { + AccessToken string `json:"access_token"` + }{} + + return tokenResp.AccessToken, json.Unmarshal(tokenBody, &tokenResp) +} diff --git a/cmd/e2e-setup/users.go b/cmd/e2e-setup/users.go new file mode 100644 index 0000000000..47f988786a --- /dev/null +++ b/cmd/e2e-setup/users.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +func listUsers(ctx context.Context, apiUrl, token string) ([]string, error) { + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, apiUrl+"/management/v1/users/_search", nil) + if err != nil { + return nil, err + } + + req.Header.Set("Authorization", "Bearer "+token) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode < 200 || resp.StatusCode > 399 { + return nil, fmt.Errorf("listing users returned status code %d and body %s", resp.StatusCode, string(bodyBytes)) + } + + unmarshalledResp := struct { + Result []struct { + UserName string `json:"userName"` + } + }{} + + if err = json.Unmarshal(bodyBytes, &unmarshalledResp); err != nil { + return nil, err + } + + users := make([]string, len(unmarshalledResp.Result)) + for i := range unmarshalledResp.Result { + users[i] = unmarshalledResp.Result[i].UserName + } + + return users, nil +} diff --git a/cmd/start/config.go b/cmd/start/config.go index ad7d161704..1b24fe5126 100644 --- a/cmd/start/config.go +++ b/cmd/start/config.go @@ -1,10 +1,11 @@ package start import ( - "time" - "github.com/mitchellh/mapstructure" "github.com/spf13/viper" + "github.com/zitadel/zitadel/internal/config/hook" + "time" + "github.com/zitadel/logging" admin_es "github.com/zitadel/zitadel/internal/admin/repository/eventsourcing" @@ -15,7 +16,6 @@ import ( "github.com/zitadel/zitadel/internal/api/ui/login" auth_es "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing" "github.com/zitadel/zitadel/internal/command" - "github.com/zitadel/zitadel/internal/config/hook" "github.com/zitadel/zitadel/internal/config/network" "github.com/zitadel/zitadel/internal/config/systemdefaults" "github.com/zitadel/zitadel/internal/crypto" @@ -54,6 +54,18 @@ type Config struct { CustomerPortal string } +type encryptionKeyConfig struct { + DomainVerification *crypto.KeyConfig + IDPConfig *crypto.KeyConfig + OIDC *crypto.KeyConfig + OTP *crypto.KeyConfig + SMS *crypto.KeyConfig + SMTP *crypto.KeyConfig + User *crypto.KeyConfig + CSRFCookieKeyID string + UserAgentCookieKeyID string +} + func MustNewConfig(v *viper.Viper) *Config { config := new(Config) @@ -73,15 +85,3 @@ func MustNewConfig(v *viper.Viper) *Config { return config } - -type encryptionKeyConfig struct { - DomainVerification *crypto.KeyConfig - IDPConfig *crypto.KeyConfig - OIDC *crypto.KeyConfig - OTP *crypto.KeyConfig - SMS *crypto.KeyConfig - SMTP *crypto.KeyConfig - User *crypto.KeyConfig - CSRFCookieKeyID string - UserAgentCookieKeyID string -} diff --git a/cmd/start/start_from_init.go b/cmd/start/start_from_init.go index 89c74d5592..cc44f18864 100644 --- a/cmd/start/start_from_init.go +++ b/cmd/start/start_from_init.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/zitadel/logging" + "github.com/zitadel/zitadel/internal/config/options" "github.com/zitadel/zitadel/cmd/initialise" "github.com/zitadel/zitadel/cmd/key" @@ -35,7 +36,7 @@ Requirements: setupSteps := setup.MustNewSteps(viper.New()) setup.Setup(setupConfig, setupSteps, masterKey) - startConfig := MustNewConfig(viper.GetViper()) + startConfig := options.MustNewConfig(viper.GetViper()) err = startZitadel(startConfig, masterKey) logging.OnError(err).Fatal("unable to start zitadel") diff --git a/cmd/zitadel.go b/cmd/zitadel.go index 0077b62885..285779a6f0 100644 --- a/cmd/zitadel.go +++ b/cmd/zitadel.go @@ -1,14 +1,13 @@ package cmd import ( - "bytes" _ "embed" "errors" "io" - "strings" + + "github.com/zitadel/zitadel/internal/config/options" "github.com/spf13/cobra" - "github.com/spf13/viper" "github.com/zitadel/logging" "github.com/zitadel/zitadel/cmd/admin" @@ -20,9 +19,6 @@ import ( var ( configFiles []string - - //go:embed defaults.yaml - defaultConfig []byte ) func New(out io.Writer, in io.Reader, args []string) *cobra.Command { @@ -35,12 +31,8 @@ func New(out io.Writer, in io.Reader, args []string) *cobra.Command { }, } - viper.AutomaticEnv() - viper.SetEnvPrefix("ZITADEL") - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - viper.SetConfigType("yaml") - err := viper.ReadConfig(bytes.NewBuffer(defaultConfig)) - logging.OnError(err).Fatal("unable to read default config") + err := options.InitViper() + logging.OnError(err).Fatalf("unable initialize config: %s", err) cobra.OnInitialize(initConfig) cmd.PersistentFlags().StringArrayVar(&configFiles, "config", nil, "path to config file to overwrite system defaults") @@ -58,9 +50,5 @@ func New(out io.Writer, in io.Reader, args []string) *cobra.Command { } func initConfig() { - for _, file := range configFiles { - viper.SetConfigFile(file) - err := viper.MergeInConfig() - logging.WithFields("file", file).OnError(err).Warn("unable to read config file") - } + options.MergeToViper(configFiles...) } diff --git a/console/e2e.env b/console/e2e.env deleted file mode 100644 index 373e72db38..0000000000 --- a/console/e2e.env +++ /dev/null @@ -1,14 +0,0 @@ -E2E_CYPRESS_PORT=5003 -E2E_ORG=e2e-tests -E2E_ORG_OWNER_PW=Password1! -E2E_ORG_OWNER_VIEWER_PW=Password1! -E2E_ORG_PROJECT_CREATOR_PW=Password1! -E2E_PASSWORD_COMPLEXITY_USER_PW=Password1! -E2E_LOGIN_POLICY_USER_PW=Password1! -E2E_SERVICEACCOUNT_KEY_PATH="${projectRoot}/.keys/e2e.json" -E2E_CONSOLE_URL="http://localhost:4200" -E2E_API_URL="http://localhost:50002" -E2E_ACCOUNTS_URL="http://localhost:50003" -E2E_ISSUER_URL="http://localhost:50002/oauth/v2" -E2E_OTHER_ZITADEL_IDP_INSTANCE=false -E2E_ZITADEL_PROJECT_RESOURCE_ID="bignumber-$(echo -n $(docker compose -f ${projectRoot}/build/local/docker-compose-local.yml exec --no-TTY db cockroach sql --insecure --execute "select aggregate_id from eventstore.events where event_type = 'project.added' and event_data = '{\"name\": \"Zitadel\"}';" --format tsv) | cut -d " " -f 2)" diff --git a/docs/docs/guides/installation/configure/configure.mdx b/docs/docs/guides/installation/configure/configure.mdx index 33b9384f05..a570710170 100644 --- a/docs/docs/guides/installation/configure/configure.mdx +++ b/docs/docs/guides/installation/configure/configure.mdx @@ -16,7 +16,7 @@ This guide assumes you are already familiar with [running ZITADEL with the most ## Configuration Files ### Runtime Configuration -See a description of all possible _runtime configuration_ options with their defaults [in the source code](https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml). +See a description of all possible _runtime configuration_ options with their defaults [in the source code](https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml). The `zitadel` binary expects the `--config` flag for this configuration. ### Database Initialization @@ -67,7 +67,7 @@ This is the IAM admin users login according to your configuration in the [exampl - Read more about [the login process](../../manuals/user-login). - If you want to run ZITADEL in production, you most certainly need to [customize your own domain](./custom-domain). -- Check out all possible [runtime configuration properties and their defaults in the source code](https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml) +- Check out all possible [runtime configuration properties and their defaults in the source code](https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml) - Check out all possible [setup step configuration properties and their defaults in the source code](https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/setup/steps.yaml) :::caution diff --git a/docs/docs/guides/installation/configure/example-zitadel-config.yaml b/docs/docs/guides/installation/configure/example-zitadel-config.yaml index 0387561e41..58a718f3be 100644 --- a/docs/docs/guides/installation/configure/example-zitadel-config.yaml +++ b/docs/docs/guides/installation/configure/example-zitadel-config.yaml @@ -1,4 +1,4 @@ -# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml Log: Level: 'info' diff --git a/docs/docs/guides/installation/configure/example-zitadel-secrets.yaml b/docs/docs/guides/installation/configure/example-zitadel-secrets.yaml index f46cb0d683..f6a0e4a7ed 100644 --- a/docs/docs/guides/installation/configure/example-zitadel-secrets.yaml +++ b/docs/docs/guides/installation/configure/example-zitadel-secrets.yaml @@ -1,4 +1,4 @@ -# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml # If not using the docker compose example, adjust these values for connecting ZITADEL to your CockroachDB Database: diff --git a/docs/docs/guides/installation/configure/example-zitadel-values-secrets.yaml b/docs/docs/guides/installation/configure/example-zitadel-values-secrets.yaml index 2475f0da34..c995b5710d 100644 --- a/docs/docs/guides/installation/configure/example-zitadel-values-secrets.yaml +++ b/docs/docs/guides/installation/configure/example-zitadel-values-secrets.yaml @@ -1,4 +1,4 @@ -# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml zitadel: masterkey: 'MasterkeyNeedsToHave32Characters' diff --git a/docs/docs/guides/installation/configure/example-zitadel-values.yaml b/docs/docs/guides/installation/configure/example-zitadel-values.yaml index 9fc6ee6223..6eaf404257 100644 --- a/docs/docs/guides/installation/configure/example-zitadel-values.yaml +++ b/docs/docs/guides/installation/configure/example-zitadel-values.yaml @@ -1,4 +1,4 @@ -# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml zitadel: configmapConfig: Log: diff --git a/docs/docs/guides/installation/loadbalancing-example/example-zitadel-config.yaml b/docs/docs/guides/installation/loadbalancing-example/example-zitadel-config.yaml index 54ee71ebff..16b4548668 100644 --- a/docs/docs/guides/installation/loadbalancing-example/example-zitadel-config.yaml +++ b/docs/docs/guides/installation/loadbalancing-example/example-zitadel-config.yaml @@ -1,4 +1,4 @@ -# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml Log: Level: 'info' diff --git a/docs/docs/guides/installation/loadbalancing-example/example-zitadel-secrets.yaml b/docs/docs/guides/installation/loadbalancing-example/example-zitadel-secrets.yaml index f46cb0d683..f6a0e4a7ed 100644 --- a/docs/docs/guides/installation/loadbalancing-example/example-zitadel-secrets.yaml +++ b/docs/docs/guides/installation/loadbalancing-example/example-zitadel-secrets.yaml @@ -1,4 +1,4 @@ -# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/cmd/defaults.yaml +# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/v2-alpha/internal/config/options/defaults.yaml # If not using the docker compose example, adjust these values for connecting ZITADEL to your CockroachDB Database: diff --git a/console/cypress.sh b/e2e/cypress.sh similarity index 100% rename from console/cypress.sh rename to e2e/cypress.sh diff --git a/e2e/docker-compose-overwrite.yaml b/e2e/docker-compose-overwrite.yaml index 3b086bd25e..7a1380fbb6 100644 --- a/e2e/docker-compose-overwrite.yaml +++ b/e2e/docker-compose-overwrite.yaml @@ -1,4 +1,3 @@ services: zitadel: image: 'zitadel:${BUILD_DATE}' - diff --git a/e2e/docker-compose.sh b/e2e/docker-compose.sh new file mode 100755 index 0000000000..6b2c81a728 --- /dev/null +++ b/e2e/docker-compose.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +COMPOSE_DOCKER_CLI_BUILD=1 docker compose --file ./docs/docs/guides/installation/run/docker-compose.yaml --file ./e2e/docker-compose-overwrite.yaml "$@" diff --git a/e2e/e2e-setup-debug.sh b/e2e/e2e-setup-debug.sh new file mode 100755 index 0000000000..179ddd5e92 --- /dev/null +++ b/e2e/e2e-setup-debug.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -ex + +projectRoot="." + +set -a +source ./e2e/local.env +set +a + +dlv debug --api-version 2 --headless --listen 127.0.0.1:2345 ./cmd/e2e-setup/*.go "$@" diff --git a/e2e/run.sh b/e2e/install.sh similarity index 73% rename from e2e/run.sh rename to e2e/install.sh index e23d3d110d..ae11b6014b 100755 --- a/e2e/run.sh +++ b/e2e/install.sh @@ -4,9 +4,8 @@ set -e DO_BUILD=1 DO_DEPLOY=1 -DO_TEST=1 -while getopts 'bdt:' OPTION; do +while getopts 'bd:' OPTION; do case "$OPTION" in b) echo "skipping build" @@ -16,15 +15,10 @@ while getopts 'bdt:' OPTION; do echo "skipping deployment" DO_DEPLOY=0 ;; - s) - echo "skipping tests" - DO_TEST=0 - ;; ?) echo "script usage: $(basename \$0) [-b] [-d] [-t]" >&2 echo "-b skip build" echo "-d skip deployment" - echo "-t skip tests" exit 1 ;; esac @@ -54,10 +48,10 @@ if [ "$DO_BUILD" -eq "1" ]; then BUILD_VERSION="$(extract_metadata metadata.json '.version')" # build the docker image - docker build --file ./build/Dockerfile --tag zitadel:latest --tag zitadel:$BUILD_VERSION --tag zitadel:$BUILD_DATE $BUILD_PATH + DOCKER_BUILDKIT=1 docker build --file ./build/Dockerfile --tag zitadel:latest --tag zitadel:$BUILD_VERSION --tag zitadel:$BUILD_DATE $BUILD_PATH fi if [ "$DO_DEPLOY" -eq "1" ]; then # run cockroach and zitadel - docker compose --file ./docs/docs/guides/installation/run/docker-compose.yaml --file ./e2e/docker-compose-overwrite.yaml up --detach + ./e2e/docker-compose.sh up --detach fi diff --git a/e2e/local.env b/e2e/local.env new file mode 100644 index 0000000000..aa2cc20413 --- /dev/null +++ b/e2e/local.env @@ -0,0 +1,14 @@ +ZITADEL_E2E_CYPRESS_PORT=5000 +ZITADEL_E2E_ORG=e2e-tests +ZITADEL_E2E_ORG_OWNER_PW=Password1! +ZITADEL_E2E_ORG_OWNER_VIEWER_PW=Password1! +ZITADEL_E2E_ORG_PROJECT_CREATOR_PW=Password1! +ZITADEL_E2E_PASSWORD_COMPLEXITY_USER_PW=Password1! +ZITADEL_E2E_LOGIN_POLICY_USER_PW=Password1! +ZITADEL_E2E_MACHINE_KEY_PATH="${projectRoot}/.keys/e2e.json" +ZITADEL_E2E_CONSOLE_URL="http://localhost:8080" +ZITADEL_E2E_API_URL="http://localhost:8080" +ZITADEL_E2E_ACCOUNTS_URL="http://localhost:8080" +ZITADEL_E2E_ISSUER_URL="http://localhost:8080/oauth/v2" +ZITADEL_E2E_OTHER_ZITADEL_IDP_INSTANCE=false +ZITADEL_E2E_ZITADEL_PROJECT_RESOURCE_ID="bignumber-$(echo -n $(./e2e/docker-compose.sh exec --no-TTY db cockroach sql --database zitadel --insecure --execute "select aggregate_id from eventstore.events where event_type = 'project.added' and event_data = '{\"name\": \"ZITADEL\"}';" --format tsv) | cut -d " " -f 2)" diff --git a/internal/config/options/defaults.go b/internal/config/options/defaults.go new file mode 100644 index 0000000000..6867e241ad --- /dev/null +++ b/internal/config/options/defaults.go @@ -0,0 +1,8 @@ +package options + +import ( + _ "embed" +) + +//go:embed defaults.yaml +var defaultConfig []byte diff --git a/cmd/defaults.yaml b/internal/config/options/defaults.yaml similarity index 100% rename from cmd/defaults.yaml rename to internal/config/options/defaults.yaml diff --git a/internal/config/options/viper.go b/internal/config/options/viper.go new file mode 100644 index 0000000000..1d4c91f5bd --- /dev/null +++ b/internal/config/options/viper.go @@ -0,0 +1,30 @@ +package options + +import ( + "bytes" + "fmt" + "strings" + + "github.com/spf13/viper" + "github.com/zitadel/logging" +) + +func InitViper() error { + viper.AutomaticEnv() + viper.SetEnvPrefix("ZITADEL") + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.SetConfigType("yaml") + err := viper.ReadConfig(bytes.NewBuffer(defaultConfig)) + if err != nil { + return fmt.Errorf("unable to read default config: %w", err) + } + return nil +} + +func MergeToViper(configFiles ...string) { + for _, file := range configFiles { + viper.SetConfigFile(file) + err := viper.MergeInConfig() + logging.WithFields("file", file).OnError(err).Warn("unable to read config file") + } +}