mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-09 20:23:41 +00:00
test(e2e): migrate e2e setup
This commit is contained in:
parent
9fbfe97d2c
commit
2b7600e6e8
118
cmd/e2e-setup/config.go
Normal file
118
cmd/e2e-setup/config.go
Normal file
@ -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
|
||||
}
|
65
cmd/e2e-setup/consistency.go
Normal file
65
cmd/e2e-setup/consistency.go
Normal file
@ -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
|
||||
}
|
110
cmd/e2e-setup/execute.go
Normal file
110
cmd/e2e-setup/execute.go
Normal file
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
139
cmd/e2e-setup/main.go
Normal file
139
cmd/e2e-setup/main.go
Normal file
@ -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))
|
||||
}
|
85
cmd/e2e-setup/token.go
Normal file
85
cmd/e2e-setup/token.go
Normal file
@ -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)
|
||||
}
|
52
cmd/e2e-setup/users.go
Normal file
52
cmd/e2e-setup/users.go
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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...)
|
||||
}
|
||||
|
@ -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)"
|
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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'
|
||||
|
@ -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:
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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:
|
||||
|
@ -1,4 +1,3 @@
|
||||
services:
|
||||
zitadel:
|
||||
image: 'zitadel:${BUILD_DATE}'
|
||||
|
||||
|
3
e2e/docker-compose.sh
Executable file
3
e2e/docker-compose.sh
Executable file
@ -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 "$@"
|
11
e2e/e2e-setup-debug.sh
Executable file
11
e2e/e2e-setup-debug.sh
Executable file
@ -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 "$@"
|
@ -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
|
14
e2e/local.env
Normal file
14
e2e/local.env
Normal file
@ -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)"
|
8
internal/config/options/defaults.go
Normal file
8
internal/config/options/defaults.go
Normal file
@ -0,0 +1,8 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed defaults.yaml
|
||||
var defaultConfig []byte
|
30
internal/config/options/viper.go
Normal file
30
internal/config/options/viper.go
Normal file
@ -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")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user