snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
185
oryx/configx/koanf_env.go
Normal file
185
oryx/configx/koanf_env.go
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package configx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
"github.com/ory/jsonschema/v3"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/ory/x/castx"
|
||||
"github.com/ory/x/jsonschemax"
|
||||
)
|
||||
|
||||
var isNumRegex = regexp.MustCompile("^[0-9]+$")
|
||||
|
||||
func NewKoanfEnv(prefix string, rawSchema []byte, schema *jsonschema.Schema) (*Env, error) {
|
||||
paths, err := getSchemaPaths(rawSchema, schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Env{
|
||||
paths: paths,
|
||||
prefix: prefix,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Env implements an environment variables provider.
|
||||
type Env struct {
|
||||
prefix string
|
||||
paths []jsonschemax.Path
|
||||
}
|
||||
|
||||
// ReadBytes is not supported by the env provider.
|
||||
func (e *Env) ReadBytes() ([]byte, error) {
|
||||
return nil, errors.New("env provider does not support this method")
|
||||
}
|
||||
|
||||
// Read reads all available environment variables into a key:value map
|
||||
// and returns it.
|
||||
func (e *Env) Read() (map[string]interface{}, error) {
|
||||
// Collect the environment variable keys.
|
||||
var keys []string
|
||||
for _, k := range os.Environ() {
|
||||
if e.prefix != "" {
|
||||
if strings.HasPrefix(k, e.prefix) {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
} else {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
|
||||
raw := "{}"
|
||||
var err error
|
||||
for _, k := range keys {
|
||||
parts := strings.SplitN(k, "=", 2)
|
||||
|
||||
key, value := e.extract(parts[0], parts[1])
|
||||
// If the callback blanked the key, it should be omitted
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
raw, err = sjson.Set(raw, key, value)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(raw), &m); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Watch is not supported.
|
||||
func (e *Env) Watch(cb func(event interface{}, err error)) error {
|
||||
return errors.New("env provider does not support this method")
|
||||
}
|
||||
|
||||
func (e *Env) extract(key string, value string) (string, interface{}) {
|
||||
key = strings.Replace(strings.ToLower(strings.TrimPrefix(key, e.prefix)), "_", ".", -1)
|
||||
|
||||
for _, path := range e.paths {
|
||||
normalized := strings.Replace(path.Name, "_", ".", -1)
|
||||
name := path.Name
|
||||
|
||||
// Crazy hack to get arrays working.
|
||||
var indices []string
|
||||
searchParts := strings.Split(normalized, ".")
|
||||
keyParts := strings.Split(key, ".")
|
||||
if len(searchParts) == len(keyParts) {
|
||||
for k, search := range searchParts {
|
||||
if search != keyParts[k] {
|
||||
indices = nil
|
||||
}
|
||||
|
||||
if search != "#" {
|
||||
continue
|
||||
}
|
||||
|
||||
if !isNumRegex.MatchString(keyParts[k]) {
|
||||
continue
|
||||
}
|
||||
|
||||
searchParts[k] = keyParts[k]
|
||||
indices = append(indices, keyParts[k])
|
||||
}
|
||||
}
|
||||
|
||||
if len(indices) > 0 {
|
||||
normalized = strings.Join(searchParts, ".")
|
||||
for _, index := range indices {
|
||||
name = strings.Replace(name, "#", index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
if normalized == key {
|
||||
switch path.TypeHint {
|
||||
case jsonschemax.String:
|
||||
return name, cast.ToString(value)
|
||||
case jsonschemax.Float:
|
||||
return name, cast.ToFloat64(value)
|
||||
case jsonschemax.Int:
|
||||
return name, cast.ToInt64(value)
|
||||
case jsonschemax.Bool:
|
||||
return name, cast.ToBool(value)
|
||||
case jsonschemax.Nil:
|
||||
return name, nil
|
||||
case jsonschemax.BoolSlice:
|
||||
if !gjson.Valid(value) {
|
||||
return name, cast.ToBoolSlice(value)
|
||||
}
|
||||
fallthrough
|
||||
case jsonschemax.StringSlice:
|
||||
if !gjson.Valid(value) {
|
||||
return name, castx.ToStringSlice(value)
|
||||
}
|
||||
fallthrough
|
||||
case jsonschemax.IntSlice:
|
||||
if !gjson.Valid(value) {
|
||||
return name, cast.ToIntSlice(value)
|
||||
}
|
||||
fallthrough
|
||||
case jsonschemax.FloatSlice:
|
||||
if !gjson.Valid(value) {
|
||||
return name, castx.ToFloatSlice(value)
|
||||
}
|
||||
fallthrough
|
||||
case jsonschemax.JSON:
|
||||
return name, decode(value)
|
||||
default:
|
||||
return name, value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func decode(value string) (v interface{}) {
|
||||
b := []byte(value)
|
||||
var arr []interface{}
|
||||
if err := json.Unmarshal(b, &arr); err == nil {
|
||||
return &arr
|
||||
}
|
||||
h := map[string]interface{}{}
|
||||
if err := json.Unmarshal(b, &h); err == nil {
|
||||
return &h
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user