snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s

This commit is contained in:
upstream-mirror
2026-09-18 01:22:23 +05:00
commit 7e385fc126
8391 changed files with 1766236 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package options
import "os"
type (
HttpServerOpt struct {
Addr string `env:"HTTP_ADDR"`
EnableHealthcheckRoute bool `env:"HTTP_ENABLE_HEALTHCHECK_ROUTE"`
EnableVersionRoute bool `env:"HTTP_ENABLE_VERSION_ROUTE"`
BaseUrl string `env:"HTTP_BASE_URL"`
ApiBaseUrl string `env:"HTTP_API_BASE_URL"`
}
)
// HttpServer initializes and returns a HTTPServerOpt with default values
func HttpServer() (o *HttpServerOpt) {
o = &HttpServerOpt{
Addr: ":80",
EnableHealthcheckRoute: true,
EnableVersionRoute: true,
BaseUrl: "/",
ApiBaseUrl: "/",
}
fill(o)
// Function that allows access to custom logic inside the parent function.
// The custom logic in the other file should be like:
// func (o *HTTPServer) Defaults() {...}
func(o interface{}) {
if def, ok := o.(interface{ Defaults() }); ok {
def.Defaults()
}
}(o)
return
}
func (o *HttpServerOpt) Defaults() {
if val, has := os.LookupEnv("PORT"); has {
o.Addr = ":" + val
}
}

View File

@@ -0,0 +1,41 @@
package options
import (
"fmt"
"github.com/cortezaproject/corteza/server/pkg/options"
)
type (
CortezaOpt struct {
BaseUrl string
AuthUrl string
DiscoveryUrl string
}
)
const (
envKeyBaseUrl = "CORTEZA_SERVER_BASE_URL"
envKeyAuthUrl = "CORTEZA_SERVER_AUTH_URL"
envKeyDiscoveryUrl = "CORTEZA_SERVER_DISCOVERY_URL"
)
func Corteza() (o *CortezaOpt, err error) {
o = &CortezaOpt{}
return o, func() error {
baseUrl := options.EnvString(envKeyBaseUrl, "http://server:80")
o.BaseUrl = baseUrl
o.AuthUrl = options.EnvString(envKeyAuthUrl, baseUrl+"/auth")
if o.AuthUrl == "" {
return fmt.Errorf("corteza Auth endpoint value empty, set it directly with %s or indirectly with %s", envKeyAuthUrl, envKeyBaseUrl)
}
o.DiscoveryUrl = options.EnvString(envKeyDiscoveryUrl, baseUrl+"/api/discovery")
if o.DiscoveryUrl == "" {
return fmt.Errorf("corteza Discovery API endpoint value empty, set it directly with %s or indirectly with %s", envKeyDiscoveryUrl, envKeyBaseUrl)
}
return nil
}()
}

View File

@@ -0,0 +1,42 @@
package options
import "strings"
type (
EnvironmentOpt struct {
Environment string `env:"ENVIRONMENT"`
}
)
// Environment initializes and returns a EnvironmentOpt with default values
func Environment() (o *EnvironmentOpt) {
o = &EnvironmentOpt{
Environment: "production",
}
fill(o)
// Function that allows access to custom logic inside the parent function.
// The custom logic in the other file should be like:
// func (o *Environment) Defaults() {...}
func(o interface{}) {
if def, ok := o.(interface{ Defaults() }); ok {
def.Defaults()
}
}(o)
return
}
func (e EnvironmentOpt) IsDevelopment() bool {
return strings.HasPrefix(e.Environment, "dev")
}
func (e EnvironmentOpt) IsTest() bool {
return strings.HasPrefix(e.Environment, "test")
}
func (e EnvironmentOpt) IsProduction() bool {
return !e.IsDevelopment() &&
!e.IsTest()
}

View File

@@ -0,0 +1,43 @@
package options
import (
"strings"
"github.com/cortezaproject/corteza/server/pkg/options"
)
type (
EsOpt struct {
Addresses []string `env:"ES_ADDRESS"`
Username string `env:"ES_USERNAME"`
Password string `env:"ES_PASSWORD"`
CertFile string `env:"ES_CERT_FILE"`
Secure bool `env:"ES_SECURE"`
EnableRetryOnTimeout bool `env:"ES_ENABLE_RETRY_ON_TIMEOUT"`
MaxRetries int `env:"ES_MAX_RETRIES"`
IndexInterval int `env:"ES_INDEX_INTERVAL"`
IndexBackFillMonths int `env:"ES_INDEX_BACKFILL_MONTHS"`
}
)
func ES() (o *EsOpt, err error) {
o = &EsOpt{}
return o, func() error {
o.Username = options.EnvString("ES_USERNAME", "")
o.Password = options.EnvString("ES_PASSWORD", "")
o.Secure = options.EnvBool("ES_SECURE", true)
o.CertFile = options.EnvString("ES_CERT_FILE", "")
o.EnableRetryOnTimeout = options.EnvBool("ES_ENABLE_RETRY_ON_TIMEOUT", true)
o.MaxRetries = options.EnvInt("ES_MAX_RETRIES", 5)
o.IndexInterval = options.EnvInt("ES_INDEX_INTERVAL", 30)
o.IndexBackFillMonths = options.EnvInt("ES_INDEX_BACKFILL_MONTHS", 0)
for _, a := range strings.Split(options.EnvString("ES_ADDRESS", "http://es:9200"), " ") {
if a = strings.TrimSpace(a); a != "" {
o.Addresses = append(o.Addresses, a)
}
}
return nil
}()
}

View File

@@ -0,0 +1,169 @@
package options
import (
"os"
"path"
"reflect"
"strings"
"time"
"github.com/spf13/cast"
)
func fill(opt interface{}) {
v := reflect.ValueOf(opt)
if v.Kind() != reflect.Ptr {
panic("expecting a pointer, not a value")
}
if v.IsNil() {
panic("nil pointer passed")
}
v = v.Elem()
length := v.NumField()
for i := 0; i < length; i++ {
f := v.Field(i)
t := v.Type().Field(i)
if tag := t.Tag.Get("env"); tag != "" {
if !f.CanSet() {
panic("unexpected pointer for field " + t.Name)
}
if f.Type() == reflect.TypeOf(time.Duration(1)) {
v.FieldByName(t.Name).SetInt(int64(EnvDuration(tag, time.Duration(f.Int()))))
continue
}
if f.Kind() == reflect.String {
v.FieldByName(t.Name).SetString(EnvString(tag, f.String()))
continue
}
if f.Kind() == reflect.Bool {
v.FieldByName(t.Name).SetBool(EnvBool(tag, f.Bool()))
continue
}
if f.Kind() == reflect.Int {
v.FieldByName(t.Name).SetInt(int64(EnvInt(tag, int(f.Int()))))
continue
}
if f.Kind() == reflect.Float32 {
v.FieldByName(t.Name).SetFloat(float64(EnvFloat32(tag, float32(f.Float()))))
continue
}
panic("unsupported type/kind for field " + t.Name)
}
}
}
func guessHostname() string {
// All env keys we'll check, first that has any value set, will be used as hostname
candidates := []string{
os.Getenv("DOMAIN"),
os.Getenv("LETSENCRYPT_HOST"),
os.Getenv("VIRTUAL_HOST"),
os.Getenv("HOSTNAME"),
os.Getenv("HOST"),
}
for _, host := range candidates {
if len(host) > 0 {
return host
}
}
return "local.cortezaproject.org"
}
// returns path prefix
func pathPrefix(pp ...string) string {
return CleanBase(append([]string{EnvString("HTTP_BASE_URL", "")}, pp...)...)
}
// will return base URL with domain and prefix path
func fullURL(pp ...string) string {
var (
full string
host = guessHostname()
)
if strings.Contains(host, "local.") || strings.Contains(host, "localhost") || !isSecure() {
full = "http://" + host
} else {
full = "https://" + host
}
if pfix := pathPrefix(pp...); pfix != "" {
return full + pfix
}
return full
}
// Checks value of HTTP_SSL_TERMINATED and fallbacks to checking existence of LETSENCRYPT_HOST
// to determinate we are behind a SSL termination infrastructure
func isSecure() bool {
var _, is = os.LookupEnv("LETSENCRYPT_HOST")
// We're accessing to HTTP_SSL_TERMINATED directly here and not via HttpServerOpt.SslTerminated
// because we need to get to this value early and directly
return EnvBool("HTTP_SSL_TERMINATED", is)
}
// Path joins all parts with / and prefixes result (if not empty) with /
func CleanBase(pp ...string) string {
//if p := strings.Trim(path.Join(pp...), "/"); p != "" {
// // prefix base with slash
// return "/" + p
//}
return "/" + strings.Trim(path.Join(pp...), "/")
}
func EnvString(key string, def string) string {
if val, has := os.LookupEnv(key); has {
return val
}
return def
}
func EnvBool(key string, def bool) bool {
if val, has := os.LookupEnv(key); has {
if b, err := cast.ToBoolE(val); err == nil {
return b
}
}
return def
}
func EnvInt(key string, def int) int {
if val, has := os.LookupEnv(key); has {
if i, err := cast.ToIntE(val); err == nil {
return i
}
}
return def
}
func EnvFloat32(key string, def float32) float32 {
if val, has := os.LookupEnv(key); has {
if i, err := cast.ToFloat32E(val); err == nil {
return i
}
}
return def
}
func EnvDuration(key string, def time.Duration) time.Duration {
if val, has := os.LookupEnv(key); has {
if d, err := cast.ToDurationE(val); err == nil {
return d
}
}
return def
}

View File

@@ -0,0 +1,91 @@
package options
import (
"fmt"
"github.com/cortezaproject/corteza/server/pkg/options"
"os"
"strings"
)
type (
IndexerOpt struct {
Enabled bool
//HttpAddr string
CortezaServerBaseUrl string
CortezaServerAuthUrl string
CortezaDiscoveryAPI string
Schemas []*schema
}
schema struct {
IndexPrefix string
ClientKey string
ClientSecret string
}
)
const (
discoveryIndexer = "DISCOVERY_INDEXER_"
indexerEnvKeyEnabled = discoveryIndexer + "ENABLED"
//indexerEnvKeyHttpAddr = discoveryIndexer + "HTTP_ADDR"
)
func Indexer() (o *IndexerOpt, err error) {
o = &IndexerOpt{}
return o, func() error {
o.Enabled = options.EnvBool(indexerEnvKeyEnabled, true)
//baseUrl := options.EnvString(envKeyBaseUrl, "http://server:80")
//o.HttpAddr = options.EnvString(indexerEnvKeyHttpAddr, "0.0.0.0:80")
//o.CortezaServerAuthUrl = options.EnvString(envKeyAuthUrl, baseUrl+"/auth")
//if o.CortezaServerAuthUrl == "" {
// return fmt.Errorf("corteza Auth endpoint value empty, set it directly with %s or indirectly with %s", envKeyAuthUrl, envKeyBaseUrl)
//}
//
//o.CortezaDiscoveryAPI = options.EnvString(envKeyDiscoveryUrl, baseUrl+"/api/discovery")
//if o.CortezaDiscoveryAPI == "" {
// return fmt.Errorf("corteza Discovery API endpoint value empty, set it directly with %s or indirectly with %s", envKeyDiscoveryUrl, envKeyBaseUrl)
//}
//o.IndexInterval = options.EnvInt(indexerEnvKeyIndexInterval, 30)
for _, ar := range []string{"public", "protected", "private"} {
var (
has bool
ucAr = strings.ToUpper(ar)
s = &schema{IndexPrefix: ar}
keyEnv = discoveryIndexer + ucAr + "_INDEX_CLIENT_KEY"
secEnv = discoveryIndexer + ucAr + "_INDEX_CLIENT_SECRET"
)
if s.ClientKey, has = os.LookupEnv(keyEnv); !has {
continue
} else if s.ClientKey == "" {
return fmt.Errorf("client key (%s) for '%s' is empty or missing", keyEnv, s.IndexPrefix)
}
if s.ClientSecret = os.Getenv(secEnv); s.ClientSecret == "" {
return fmt.Errorf("client secret (%s) for '%s' is empty or missing", secEnv, s.IndexPrefix)
}
o.Schemas = append(o.Schemas, s)
}
if len(o.Schemas) == 0 {
return fmt.Errorf("set at least one client secret pair using %s<PREFIX>_INDEX_CLIENT_KEY and <PREFIX>_INDEX_CLIENT_SECRET where prefix is one of 'public', 'protected' or 'private'", discoveryIndexer)
}
//for _, a := range strings.Split(options.EnvString(indexerEnvKeyEsAddr, "http://es:9200"), " ") {
// if a = strings.TrimSpace(a); a != "" {
// o.Es.Addresses = append(o.Es.Addresses, a)
// }
//}
return nil
}()
}

View File

@@ -0,0 +1,47 @@
package options
type (
Options struct {
Corteza CortezaOpt
ES EsOpt
Indexer IndexerOpt
Searcher SearcherOpt
Environment EnvironmentOpt
HTTPServer HttpServerOpt
WaitFor WaitForOpt
}
)
// @todo: add codegen for options
func Init() (opt *Options, err error) {
indexer, err := Indexer()
if err != nil {
return
}
searcher, err := Searcher()
if err != nil {
return
}
es, err := ES()
if err != nil {
return
}
corteza, err := Corteza()
if err != nil {
return
}
return &Options{
Corteza: *corteza,
ES: *es,
Indexer: *indexer,
Searcher: *searcher,
Environment: *Environment(),
HTTPServer: *HttpServer(),
WaitFor: *WaitFor(),
}, nil
}

View File

@@ -0,0 +1,82 @@
package options
import (
"fmt"
"os"
"strings"
"github.com/cortezaproject/corteza/server/pkg/options"
)
type (
SearcherOpt struct {
Enabled bool
//HttpAddr string
JwtSecret []byte
ClientKey string
ClientSecret string
// temp fix: remove it once allowed role is fixed on server
AllowedRole map[interface{}]bool
}
)
const (
discoverySearcher = "DISCOVERY_SEARCHER_"
searcherEnvKeyEnabled = discoverySearcher + "ENABLED"
//searcherEnvKeyHttpAddr = discoverySearcher + "HTTP_ADDR"
envKeyJwtSecret = discoverySearcher + "JWT_SECRET"
envKeyClientKey = discoverySearcher + "CLIENT_KEY"
envKeyClientSecret = discoverySearcher + "CLIENT_SECRET"
envKeyAllowedRole = discoverySearcher + "ALLOWED_ROLE"
)
func Searcher() (*SearcherOpt, error) {
o := &SearcherOpt{}
return o, func() error {
o.Enabled = options.EnvBool(searcherEnvKeyEnabled, true)
//o.CortezaServerBaseUrl = options.EnvString(envKeyBaseUrl, "http://server:80")
//if o.CortezaServerBaseUrl == "" {
// return fmt.Errorf("endpoint URL for corteza (%s) is empty or missing", envKeyAuthUrl)
//}
//o.HttpAddr = options.EnvString(searcherEnvKeyHttpAddr, "0.0.0.0:80")
//o.CortezaServerAuthUrl = options.EnvString(envKeyAuthUrl, o.CortezaServerBaseUrl+"/auth")
//if o.CortezaServerAuthUrl == "" {
// return fmt.Errorf("endpoint URL for corteza auth (%s) is empty or missing", envKeyAuthUrl)
//}
if tmp := os.Getenv(envKeyJwtSecret); tmp != "" {
o.JwtSecret = []byte(tmp)
}
if o.ClientKey = os.Getenv(envKeyClientKey); o.ClientKey == "" {
return fmt.Errorf("client key (%s) is empty or missing", envKeyClientKey)
}
if o.ClientSecret = os.Getenv(envKeyClientSecret); o.ClientSecret == "" {
return fmt.Errorf("client secret (%s) is empty or missing", envKeyClientSecret)
}
for _, a := range strings.Split(options.EnvString(envKeyAllowedRole, ""), " ") {
o.AllowedRole = make(map[interface{}]bool)
if a = strings.TrimSpace(a); a != "" {
o.AllowedRole[a] = false
}
}
//for _, a := range strings.Split(options.EnvString(envKeyEsAddr, "http://localhost:9200"), " ") {
// if a = strings.TrimSpace(a); a != "" {
// o.Es.Addresses = append(o.Es.Addresses, a)
// }
//}
//o.EnableRetryOnTimeout = options.EnvBool(searcherEnvKeyEsEnableRetryOnTimeout, true)
//o.MaxRetries = options.EnvInt(searcherEnvKeyEsMaxRetries, 5)
return nil
}()
}

View File

@@ -0,0 +1,33 @@
package options
import (
"time"
)
type (
WaitForOpt struct {
Delay time.Duration `env:"WAIT_FOR"`
StatusPage bool `env:"WAIT_FOR_STATUS_PAGE"`
}
)
// WaitFor initializes and returns a WaitForOpt with default values
func WaitFor() (o *WaitForOpt) {
o = &WaitForOpt{
Delay: 0,
StatusPage: true,
}
fill(o)
// Function that allows access to custom logic inside the parent function.
// The custom logic in the other file should be like:
// func (o *WaitFor) Defaults() {...}
func(o interface{}) {
if def, ok := o.(interface{ Defaults() }); ok {
def.Defaults()
}
}(o)
return
}