pax_global_header00006660000000000000000000000064145401764350014523gustar00rootroot0000000000000052 comment=27e15c0da04ef6826e9c044fa176a2882f9e5f9a koanf-providers-vault-v2.0.1/000077500000000000000000000000001454017643500161535ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/.github/000077500000000000000000000000001454017643500175135ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001454017643500216765ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000010001454017643500243570ustar00rootroot00000000000000--- name: Bug report about: Create a bug report title: '' labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps / breaking unit test / example to reproduce the behavior **Expected behavior** A clear and concise description of what you expected to happen. **Please provide the following information):** - OS: [e.g. linux/osx/windows] - Koanf Version [e.g. v1.0.0] **Additional context** Add any other context about the problem here. koanf-providers-vault-v2.0.1/.github/workflows/000077500000000000000000000000001454017643500215505ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/.github/workflows/test.yml000066400000000000000000000011351454017643500232520ustar00rootroot00000000000000name: Run Tests # Triggers the workflow on push or pull request events on: [push, pull_request] jobs: test: strategy: matrix: go: [ '1.18', '1.19', '1.20' ] runs-on: ubuntu-20.04 name: Go ${{ matrix.go }} Tests steps: - uses: actions/checkout@v3 - name: Setup Go uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} - name: Run tests run: go test -v ./... - name: Run tests in test directory run: cd tests && go test -v ./... - name: Run Coverage run: go test -v -cover ./... koanf-providers-vault-v2.0.1/.gitignore000066400000000000000000000000221454017643500201350ustar00rootroot00000000000000.env # IDE .idea koanf-providers-vault-v2.0.1/LICENSE000066400000000000000000000021141454017643500171560ustar00rootroot00000000000000The MIT License Copyright (c) 2019, Kailash Nadh. https://github.com/knadh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. koanf-providers-vault-v2.0.1/README.md000066400000000000000000000723171454017643500174440ustar00rootroot00000000000000 ![koanf](https://user-images.githubusercontent.com/547147/72681838-6981dd00-3aed-11ea-8f5d-310816c70c08.png) **koanf** is a library for reading configuration from different sources in different formats in Go applications. It is a cleaner, lighter [alternative to spf13/viper](#alternative-to-viper) with better abstractions and extensibility and far fewer dependencies. koanf v2 has modules (Providers) for reading configuration from a variety of sources such as files, command line flags, environment variables, Vault, and S3 and for parsing (Parsers) formats such as JSON, YAML, TOML, Hashicorp HCL. It is easy to plug in custom parsers and providers. All external dependencies in providers and parsers are detached from the core and can be installed separately as necessary. [![Run Tests](https://github.com/knadh/koanf/actions/workflows/test.yml/badge.svg)](https://github.com/knadh/koanf/actions/workflows/test.yml) [![GoDoc](https://godoc.org/github.com/knadh/koanf?status.svg)](https://godoc.org/github.com/knadh/koanf) ### Installation ```shell # Install the core. go get -u github.com/knadh/koanf/v2 # Install the necessary Provider(s). # Available: file, env, posflag, basicflag, confmap, rawbytes, # structs, fs, s3, appconfig/v2, consul/v2, etcd/v2, vault/v2, parameterstore/v2 # eg: go get -u github.com/knadh/koanf/providers/s3 # eg: go get -u github.com/knadh/koanf/providers/consul/v2 go get -u github.com/knadh/koanf/providers/file # Install the necessary Parser(s). # Available: toml, json, yaml, dotenv, hcl, hjson, nestedtext # go get -u github.com/knadh/koanf/parsers/$parser go get -u github.com/knadh/koanf/parsers/toml ``` [See the list](#api) of all bundled Providers and Parsers. ### Contents - [Concepts](#concepts) - [Reading config from files](#reading-config-from-files) - [Watching file for changes](#watching-file-for-changes) - [Reading from command line](#reading-from-command-line) - [Reading environment variables](#reading-environment-variables) - [Reading raw bytes](#reading-raw-bytes) - [Reading from maps and structs](#reading-from-nested-maps) - [Unmarshalling and marshalling](#unmarshalling-and-marshalling) - [Order of merge and key case senstivity](#order-of-merge-and-key-case-sensitivity) - [Custom Providers and Parsers](#custom-providers-and-parsers) - [Custom merge strategies](#custom-merge-strategies) - [List of installable Providers and Parsers](#api) ### Concepts - `koanf.Provider` is a generic interface that provides configuration, for example, from files, environment variables, HTTP sources, or anywhere. The configuration can either be raw bytes that a parser can parse, or it can be a nested `map[string]interface{}` that can be directly loaded. - `koanf.Parser` is a generic interface that takes raw bytes, parses, and returns a nested `map[string]interface{}`. For example, JSON and YAML parsers. - Once loaded into koanf, configuration are values queried by a delimited key path syntax. eg: `app.server.port`. Any delimiter can be chosen. - Configuration from multiple sources can be loaded and merged into a koanf instance, for example, load from a file first and override certain values with flags from the command line. With these two interface implementations, koanf can obtain configuration in any format from any source, parse it, and make it available to an application. ### Reading config from files ```go package main import ( "fmt" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load YAML config and merge into the previously loaded config (because we can). k.Load(file.Provider("mock/mock.yml"), yaml.Parser()) fmt.Println("parent's name is = ", k.String("parent1.name")) fmt.Println("parent's ID is = ", k.Int("parent1.id")) } ``` ### Watching file for changes Some providers expose a `Watch()` method that makes the provider watch for changes in configuration and trigger a callback to reload the configuration. This is not goroutine safe if there are concurrent `*Get()` calls happening on the koanf object while it is doing a `Load()`. Such scenarios will need mutex locking. `file, appconfig, vault, consul` providers have a `Watch()` method. ```go package main import ( "fmt" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Load JSON config. f := file.Provider("mock/mock.json") if err := k.Load(f, json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load YAML config and merge into the previously loaded config (because we can). k.Load(file.Provider("mock/mock.yml"), yaml.Parser()) fmt.Println("parent's name is = ", k.String("parent1.name")) fmt.Println("parent's ID is = ", k.Int("parent1.id")) // Watch the file and get a callback on change. The callback can do whatever, // like re-load the configuration. // File provider always returns a nil `event`. f.Watch(func(event interface{}, err error) { if err != nil { log.Printf("watch error: %v", err) return } // Throw away the old config and load a fresh copy. log.Println("config changed. Reloading ...") k = koanf.New(".") k.Load(f, json.Parser()) k.Print() }) // Block forever (and manually make a change to mock/mock.json) to // reload the config. log.Println("waiting forever. Try making a change to mock/mock.json to live reload") <-make(chan bool) } ``` ### Reading from command line The following example shows the use of `posflag.Provider`, a wrapper over the [spf13/pflag](https://github.com/spf13/pflag) library, an advanced commandline lib. For Go's built in `flag` package, use `basicflag.Provider`. ```go package main import ( "fmt" "log" "os" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/toml" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/posflag" flag "github.com/spf13/pflag" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Use the POSIX compliant pflag lib instead of Go's flag lib. f := flag.NewFlagSet("config", flag.ContinueOnError) f.Usage = func() { fmt.Println(f.FlagUsages()) os.Exit(0) } // Path to one or more config files to load into koanf along with some config params. f.StringSlice("conf", []string{"mock/mock.toml"}, "path to one or more .toml config files") f.String("time", "2020-01-01", "a time string") f.String("type", "xxx", "type of the app") f.Parse(os.Args[1:]) // Load the config files provided in the commandline. cFiles, _ := f.GetStringSlice("conf") for _, c := range cFiles { if err := k.Load(file.Provider(c), toml.Parser()); err != nil { log.Fatalf("error loading file: %v", err) } } // "time" and "type" may have been loaded from the config file, but // they can still be overridden with the values from the command line. // The bundled posflag.Provider takes a flagset from the spf13/pflag lib. // Passing the Koanf instance to posflag helps it deal with default command // line flag values that are not present in conf maps from previously loaded // providers. if err := k.Load(posflag.Provider(f, ".", k), nil); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println("time is = ", k.String("time")) } ``` ### Reading environment variables ```go package main import ( "fmt" "log" "strings" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var k = koanf.New(".") func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load environment variables and merge into the loaded config. // "MYVAR" is the prefix to filter the env vars by. // "." is the delimiter used to represent the key hierarchy in env vars. // The (optional, or can be nil) function can be used to transform // the env var names, for instance, to lowercase them. // // For example, env vars: MYVAR_TYPE and MYVAR_PARENT1_CHILD1_NAME // will be merged into the "type" and the nested "parent1.child1.name" // keys in the config file here as we lowercase the key, // replace `_` with `.` and strip the MYVAR_ prefix so that // only "parent1.child1.name" remains. k.Load(env.Provider("MYVAR_", ".", func(s string) string { return strings.Replace(strings.ToLower( strings.TrimPrefix(s, "MYVAR_")), "_", ".", -1) }), nil) fmt.Println("name is = ", k.String("parent1.child1.name")) } ``` You can also use the `env.ProviderWithValue` with a callback that supports mutating both the key and value to return types other than a string. For example, here, env values separated by spaces are returned as string slices or arrays. eg: `MYVAR_slice=a b c` becomes `slice: [a, b, c]`. ```go k.Load(env.ProviderWithValue("MYVAR_", ".", func(s string, v string) (string, interface{}) { // Strip out the MYVAR_ prefix and lowercase and get the key while also replacing // the _ character with . in the key (koanf delimeter). key := strings.Replace(strings.ToLower(strings.TrimPrefix(s, "MYVAR_")), "_", ".", -1) // If there is a space in the value, split the value into a slice by the space. if strings.Contains(v, " ") { return key, strings.Split(v, " ") } // Otherwise, return the plain string. return key, v }), nil) ``` ### Reading from an S3 bucket ```go // Load JSON config from s3. if err := k.Load(s3.Provider(s3.Config{ AccessKey: os.Getenv("AWS_S3_ACCESS_KEY"), SecretKey: os.Getenv("AWS_S3_SECRET_KEY"), Region: os.Getenv("AWS_S3_REGION"), Bucket: os.Getenv("AWS_S3_BUCKET"), ObjectKey: "dir/config.json", }), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } ``` ### Reading raw bytes The bundled `rawbytes` Provider can be used to read arbitrary bytes from a source, like a database or an HTTP call. ```go package main import ( "fmt" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/rawbytes" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var k = koanf.New(".") func main() { b := []byte(`{"type": "rawbytes", "parent1": {"child1": {"type": "rawbytes"}}}`) k.Load(rawbytes.Provider(b), json.Parser()) fmt.Println("type is = ", k.String("parent1.child1.type")) } ``` ### Unmarshalling and marshalling `Parser`s can be used to unmarshal and scan the values in a Koanf instance into a struct based on the field tags, and to marshal a Koanf instance back into serialized bytes, for example, back to JSON or YAML, to write back to files. ```go package main import ( "fmt" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/file" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var ( k = koanf.New(".") parser = json.Parser() ) func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), parser); err != nil { log.Fatalf("error loading config: %v", err) } // Structure to unmarshal nested conf to. type childStruct struct { Name string `koanf:"name"` Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` GrandChild struct { Ids []int `koanf:"ids"` On bool `koanf:"on"` } `koanf:"grandchild1"` } var out childStruct // Quick unmarshal. k.Unmarshal("parent1.child1", &out) fmt.Println(out) // Unmarshal with advanced config. out = childStruct{} k.UnmarshalWithConf("parent1.child1", &out, koanf.UnmarshalConf{Tag: "koanf"}) fmt.Println(out) // Marshal the instance back to JSON. // The paser instance can be anything, eg: json.Paser(), yaml.Parser() etc. b, _ := k.Marshal(parser) fmt.Println(string(b)) } ``` ### Unmarshalling with flat paths Sometimes it is necessary to unmarshal an assortment of keys from various nested structures into a flat target structure. This is possible with the `UnmarshalConf.FlatPaths` flag. ```go package main import ( "fmt" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/file" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var k = koanf.New(".") func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } type rootFlat struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1Name string `koanf:"parent1.name"` Parent1ID int `koanf:"parent1.id"` Parent1Child1Name string `koanf:"parent1.child1.name"` Parent1Child1Type string `koanf:"parent1.child1.type"` Parent1Child1Empty map[string]string `koanf:"parent1.child1.empty"` Parent1Child1Grandchild1IDs []int `koanf:"parent1.child1.grandchild1.ids"` Parent1Child1Grandchild1On bool `koanf:"parent1.child1.grandchild1.on"` } // Unmarshal the whole root with FlatPaths: True. var o1 rootFlat k.UnmarshalWithConf("", &o1, koanf.UnmarshalConf{Tag: "koanf", FlatPaths: true}) fmt.Println(o1) // Unmarshal a child structure of "parent1". type subFlat struct { Name string `koanf:"name"` ID int `koanf:"id"` Child1Name string `koanf:"child1.name"` Child1Type string `koanf:"child1.type"` Child1Empty map[string]string `koanf:"child1.empty"` Child1Grandchild1IDs []int `koanf:"child1.grandchild1.ids"` Child1Grandchild1On bool `koanf:"child1.grandchild1.on"` } var o2 subFlat k.UnmarshalWithConf("parent1", &o2, koanf.UnmarshalConf{Tag: "koanf", FlatPaths: true}) fmt.Println(o2) } ``` #### Reading from nested maps The bundled `confmap` provider takes a `map[string]interface{}` that can be loaded into a koanf instance. ```go package main import ( "fmt" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Load default values using the confmap provider. // We provide a flat map with the "." delimiter. // A nested map can be loaded by setting the delimiter to an empty string "". k.Load(confmap.Provider(map[string]interface{}{ "parent1.name": "Default Name", "parent3.name": "New name here", }, "."), nil) // Load JSON config on top of the default values. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load YAML config and merge into the previously loaded config (because we can). k.Load(file.Provider("mock/mock.yml"), yaml.Parser()) fmt.Println("parent's name is = ", k.String("parent1.name")) fmt.Println("parent's ID is = ", k.Int("parent1.id")) } ``` #### Reading from struct The bundled `structs` provider can be used to read data from a struct to load into a koanf instance. ```go package main import ( "fmt" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/providers/structs" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") type parentStruct struct { Name string `koanf:"name"` ID int `koanf:"id"` Child1 childStruct `koanf:"child1"` } type childStruct struct { Name string `koanf:"name"` Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Grandchild1 grandchildStruct `koanf:"grandchild1"` } type grandchildStruct struct { Ids []int `koanf:"ids"` On bool `koanf:"on"` } type sampleStruct struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1 parentStruct `koanf:"parent1"` } func main() { // Load default values using the structs provider. // We provide a struct along with the struct tag `koanf` to the // provider. k.Load(structs.Provider(sampleStruct{ Type: "json", Empty: make(map[string]string), Parent1: parentStruct{ Name: "parent1", ID: 1234, Child1: childStruct{ Name: "child1", Type: "json", Empty: make(map[string]string), Grandchild1: grandchildStruct{ Ids: []int{1, 2, 3}, On: true, }, }, }, }, "koanf"), nil) fmt.Printf("name is = `%s`\n", k.String("parent1.child1.name")) } ``` ### Merge behavior #### Default behavior The default behavior when you create Koanf this way is: `koanf.New(delim)` that the latest loaded configuration will merge with the previous one. For example: `first.yml` ```yaml key: [1,2,3] ``` `second.yml` ```yaml key: 'string' ``` When `second.yml` is loaded it will override the type of the `first.yml`. If this behavior is not desired, you can merge 'strictly'. In the same scenario, `Load` will return an error. ```go package main import ( "errors" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/maps" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" ) var conf = koanf.Conf{ Delim: ".", StrictMerge: true, } var k = koanf.NewWithConf(conf) func main() { yamlPath := "mock/mock.yml" if err := k.Load(file.Provider(yamlPath), yaml.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } jsonPath := "mock/mock.json" if err := k.Load(file.Provider(jsonPath), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } } ``` **Note:** When merging different extensions, each parser can treat his types differently, meaning even though you the load same types there is a probability that it will fail with `StrictMerge: true`. For example: merging JSON and YAML will most likely fail because JSON treats integers as float64 and YAML treats them as integers. ### Order of merge and key case sensitivity - Config keys are case-sensitive in koanf. For example, `app.server.port` and `APP.SERVER.port` are not the same. - koanf does not impose any ordering on loading config from various providers. Every successive `Load()` or `Merge()` merges new config into the existing config. That is, it is possible to load environment variables first, then files on top of it, and then command line variables on top of it, or any such order. ### Custom Providers and Parsers A Provider returns a nested `map[string]interface{}` config that can be loaded directly into koanf with `koanf.Load()` or it can return raw bytes that can be parsed with a Parser (again, loaded using `koanf.Load()`. Writing Providers and Parsers are easy. See the bundled implementations in the [providers](https://github.com/knadh/koanf/tree/master/providers) and [parsers](https://github.com/knadh/koanf/tree/master/parsers) directories. ### Custom merge strategies By default, when merging two config sources using `Load()`, koanf recursively merges keys of nested maps (`map[string]interface{}`), while static values are overwritten (slices, strings, etc). This behaviour can be changed by providing a custom merge function with the `WithMergeFunc` option. ```go package main import ( "errors" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/maps" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" ) var conf = koanf.Conf{ Delim: ".", StrictMerge: true, } var k = koanf.NewWithConf(conf) func main() { yamlPath := "mock/mock.yml" if err := k.Load(file.Provider(yamlPath), yaml.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } jsonPath := "mock/mock.json" if err := k.Load(file.Provider(jsonPath), json.Parser(), koanf.WithMergeFunc(func(src, dest map[string]interface{}) error { // Your custom logic, copying values from src into dst return nil })); err != nil { log.Fatalf("error loading config: %v", err) } } ``` ## API See the full API documentation of all available methods at https://pkg.go.dev/github.com/knadh/koanf/v2#section-documentation ### Bundled Providers Install with `go get -u github.com/knadh/koanf/providers/$provider` | Package | Provider | Description | | ------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | file | `file.Provider(filepath string)` | Reads a file and returns the raw bytes to be parsed. | | fs | `fs.Provider(f fs.FS, filepath string)` | (**Experimental**) Reads a file from fs.FS and returns the raw bytes to be parsed. The provider requires `go v1.16` or higher. | | basicflag | `basicflag.Provider(f *flag.FlagSet, delim string)` | Takes an stdlib `flag.FlagSet` | | posflag | `posflag.Provider(f *pflag.FlagSet, delim string)` | Takes an `spf13/pflag.FlagSet` (advanced POSIX compatible flags with multiple types) and provides a nested config map based on delim. | | env | `env.Provider(prefix, delim string, f func(s string) string)` | Takes an optional prefix to filter env variables by, an optional function that takes and returns a string to transform env variables, and returns a nested config map based on delim. | | confmap | `confmap.Provider(mp map[string]interface{}, delim string)` | Takes a premade `map[string]interface{}` conf map. If delim is provided, the keys are assumed to be flattened, thus unflattened using delim. | | structs | `structs.Provider(s interface{}, tag string)` | Takes a struct and struct tag. | | s3 | `s3.Provider(s3.S3Config{})` | Takes a s3 config struct. | | rawbytes | `rawbytes.Provider(b []byte)` | Takes a raw `[]byte` slice to be parsed with a koanf.Parser | | vault/v2 | `vault.Provider(vault.Config{})` | Hashicorp Vault provider | | appconfig/v2 | `vault.AppConfig(appconfig.Config{})` | AWS AppConfig provider | | etcd/v2 | `etcd.Provider(etcd.Config{})` | CNCF etcd provider | | consul/v2 | `consul.Provider(consul.Config{})` | Hashicorp Consul provider | | parameterstore/v2 | `parameterstore.Provider(parameterstore.Config{})` | AWS Systems Manager Parameter Store provider | ### Bundled Parsers Install with `go get -u github.com/knadh/koanf/parsers/$parser` | Package | Parser | Description | | ------------ | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | json | `json.Parser()` | Parses JSON bytes into a nested map | | yaml | `yaml.Parser()` | Parses YAML bytes into a nested map | | toml | `toml.Parser()` | Parses TOML bytes into a nested map | | dotenv | `dotenv.Parser()` | Parses DotEnv bytes into a flat map | | hcl | `hcl.Parser(flattenSlices bool)` | Parses Hashicorp HCL bytes into a nested map. `flattenSlices` is recommended to be set to true. [Read more](https://github.com/hashicorp/hcl/issues/162). | | nestedtext | `nestedtext.Parser()` | Parses NestedText bytes into a flat map | | hjson | `hjson.Parser()` | Parses HJSON bytes into a nested map | ### Third-party Providers | Package | Provider | Description | | ------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | github.com/defensestation/koanf/providers/secretsmanager | `vault.SecretsMananger(secretsmanager.Config{}, f func(s string) string)` | AWS Secrets Manager provider, takes map or string as a value from store | | github.com/defensestation/koanf/providers/parameterstore | `vault.ParameterStore(parameterstore.Config{}, f func(s string) string)` | AWS ParameterStore provider, an optional function that takes and returns a string to transform env variables | ### Alternative to viper koanf is a [lightweight](https://github.com/knadh/koanf/blob/master/go.mod) alternative to the popular [spf13/viper](https://github.com/spf13/viper). It was written as a result of multiple stumbling blocks encountered with some of viper's fundamental flaws. - viper breaks JSON, YAML, TOML, HCL language specs by [forcibly lowercasing keys](https://github.com/spf13/viper/pull/635). - Significantly bloats [build sizes](https://github.com/knadh/koanf/wiki/Comparison-with-spf13-viper). - Tightly couples config parsing with file extensions. - Has poor semantics and abstractions. Commandline, env, file etc. and various parses are hardcoded in the core. There are no primitives that can be extended. - Pulls a large number of [third party dependencies](https://github.com/spf13/viper/issues/707) into the core package. For instance, even if you do not use YAML or flags, the dependencies are still pulled as a result of the coupling. - Imposes arbitrary ordering conventions (eg: flag -> env -> config etc.) - `Get()` returns references to slices and maps. Mutations made outside change the underlying values inside the conf map. - Does non-idiomatic things such as [throwing away O(1) on flat maps](https://github.com/spf13/viper/blob/3b4aca75714a37276c4b1883630bd98c02498b73/viper.go#L1524). - Viper treats keys that contain an empty map (eg: `my_key: {}`) as if they were not set (ie: `IsSet("my_key") == false`). - There are a large number of [open issues](https://github.com/spf13/viper/issues). koanf-providers-vault-v2.0.1/examples/000077500000000000000000000000001454017643500177715ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/complex-etcd/000077500000000000000000000000001454017643500223555ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/complex-etcd/data.json000066400000000000000000000002531454017643500241610ustar00rootroot00000000000000{ "parent1": "father", "parent2": "mother", "child1": "Alex", "child2": "Julia", "child3": "Michael", "child4": "Natalie", "child5": "Rosalind", "child6": "Tim" } koanf-providers-vault-v2.0.1/examples/complex-etcd/koanfetcd.sh000077500000000000000000000005421454017643500246530ustar00rootroot00000000000000# Testing script. Requirements: installed etcd # setting the directory for the etcd CURRENT_DIR=`pwd` ETCD_TESTDIR="$CURRENT_DIR/etcdtest" etcd --data-dir "$ETCD_TESTDIR" & etcdctl endpoint health --dial-timeout=4s # main test echo -e "\nChecking...\n" go run main.go ETCD_PID=`pidof etcd` kill -9 $ETCD_PID rm -rf "$ETCD_TESTDIR" #rm k_etcd_check koanf-providers-vault-v2.0.1/examples/complex-etcd/main.go000066400000000000000000000152641454017643500236400ustar00rootroot00000000000000// Example and test package main import ( "context" "fmt" "log" "os/exec" "strings" "time" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/etcd/v2" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" clientv3 "go.etcd.io/etcd/client/v3" ) var ( kData = koanf.New(".") kReq = koanf.New(".") kCheck = koanf.New(".") ) func main() { if err := kData.Load(file.Provider("data.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{"localhost:2379"}, DialTimeout: time.Second * 2, }) if err != nil { log.Fatal("Cannot create a client by clientv3.New().") } defer cli.Close() keysData := kData.Keys() for i := 0; i < len(keysData); i++ { ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) _, err := cli.Put(ctx, keysData[i], kData.String(keysData[i])) cancel() if err != nil { log.Printf("Couldn't put key.") } } // Single key/value. var ( sKey = "single_key" sVal = "single_val" ) ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) _, err = cli.Put(ctx, sKey, sVal) defer cancel() if err != nil { log.Printf("Couldn't put key.") } providerCfg := etcd.Config{ Endpoints: []string{"localhost:2379"}, DialTimeout: time.Second * 5, Prefix: false, Key: "single_key", } provider, err := etcd.Provider(providerCfg) if err != nil { log.Fatalf("Failed to instantiate etcd provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } if len(kCheck.Keys()) != 1 { fmt.Println(len(kCheck.Keys())) fmt.Printf("Single key: FAILED\n") return } if strings.Compare(sKey, kCheck.Keys()[0]) != 0 { fmt.Printf("Single key: key comparison FAILED\n") return } if strings.Compare(sVal, kCheck.String(kCheck.Keys()[0])) != 0 { fmt.Printf("Single key: value comparison FAILED\n") return } fmt.Printf("\nSingle key test passed.\n") kCheck.Delete("") // first request test // analog of the command: // etcdctl get --prefix parent if err := kReq.Load(file.Provider("req1.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } providerCfg = etcd.Config{ Endpoints: []string{"localhost:2379"}, DialTimeout: time.Second * 5, Prefix: true, Key: "parent", } provider, err = etcd.Provider(providerCfg) if err != nil { log.Fatalf("Failed to instantiate etcd provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } keysReq := kReq.Keys() keysCheck := kCheck.Keys() if len(keysReq) != len(keysCheck) { fmt.Printf("First request: keys FAILED\n") return } for i := 0; i < len(keysReq); i++ { if strings.Compare(keysReq[i], keysCheck[i]) != 0 { fmt.Printf("First request: key comparison FAILED\n") return } if strings.Compare(kReq.String(keysReq[i]), kCheck.String(keysCheck[i])) != 0 { fmt.Printf("First request: value comparison FAILED\n") return } } fmt.Printf("First request test passed.\n") kReq.Delete("") kCheck.Delete("") // second request test // analog of the command: // etcdctl get --prefix child if err := kReq.Load(file.Provider("req2.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } providerCfg = etcd.Config{ Endpoints: []string{"localhost:2379"}, DialTimeout: time.Second * 5, Prefix: true, Key: "child", } provider, err = etcd.Provider(providerCfg) if err != nil { log.Fatalf("Failed to instantiate etcd provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } keysReq = kReq.Keys() keysCheck = kCheck.Keys() if len(keysReq) != len(keysCheck) { fmt.Printf("Second request: keys FAILED\n") return } for i := 0; i < len(keysReq); i++ { if strings.Compare(keysReq[i], keysCheck[i]) != 0 { fmt.Printf("Second request: key comparison FAILED\n") return } if strings.Compare(kReq.String(keysReq[i]), kCheck.String(keysCheck[i])) != 0 { fmt.Printf("Second request: value comparison FAILED\n") return } } fmt.Printf("Second request test passed.\n") kReq.Delete("") kCheck.Delete("") // third (combined prefix + limit) request test // analog of the command: // etcdctl get --prefix child --limit=4 if err := kReq.Load(file.Provider("req3.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } providerCfg = etcd.Config{ Endpoints: []string{"localhost:2379"}, DialTimeout: time.Second * 5, Prefix: true, Limit: true, NLimit: 4, Key: "child", } provider, err = etcd.Provider(providerCfg) if err != nil { log.Fatalf("Failed to instantiate etcd provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } keysReq = kReq.Keys() keysCheck = kCheck.Keys() if len(keysReq) != len(keysCheck) { fmt.Printf("Third request: keys FAILED\n") return } for i := 0; i < len(keysReq); i++ { if strings.Compare(keysReq[i], keysCheck[i]) != 0 { fmt.Printf("Third request: key comparison FAILED\n") return } if strings.Compare(kReq.String(keysReq[i]), kCheck.String(keysCheck[i])) != 0 { fmt.Printf("Third request: value comparison FAILED\n") return } } fmt.Printf("Third (combined) request test passed.\n") kCheck.Delete("") // Watch test sKey = "child" providerCfg = etcd.Config{ Endpoints: []string{"localhost:2379"}, DialTimeout: time.Second * 5, Prefix: true, Key: "child", } provider, err = etcd.Provider(providerCfg) if err != nil { log.Fatalf("Failed to instantiate etcd provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } changedC := make(chan string, 1) provider.Watch(func(event interface{}, err error) { if err != nil { fmt.Printf("Unexpected error: %v", err) return } kCheck.Load(provider, nil) changedC <- kCheck.String(string(event.(*clientv3.Event).Kv.Key)) }) var newVal string = "Brian" cmd := exec.Command("etcdctl", "put", "child1", newVal) err = cmd.Run() if err != nil { log.Fatal(err) } if strings.Compare(newVal, <-changedC) != 0 { fmt.Printf("Watch failed: new value comparison FAILED\n") return } newVal = "Kate" cmd = exec.Command("etcdctl", "put", "child2", newVal) err = cmd.Run() if err != nil { log.Fatal(err) } if strings.Compare(newVal, <-changedC) != 0 { fmt.Printf("Watch failed: new value comparison FAILED\n") return } fmt.Printf("Watch test passed.\n") fmt.Printf("ALL TESTS PASSED\n") } koanf-providers-vault-v2.0.1/examples/complex-etcd/req1.json000066400000000000000000000000571454017643500241220ustar00rootroot00000000000000{ "parent1": "father", "parent2": "mother" } koanf-providers-vault-v2.0.1/examples/complex-etcd/req2.json000066400000000000000000000001771454017643500241260ustar00rootroot00000000000000{ "child1": "Alex", "child2": "Julia", "child3": "Michael", "child4": "Natalie", "child5": "Rosalind", "child6": "Tim" } koanf-providers-vault-v2.0.1/examples/complex-etcd/req3.json000066400000000000000000000001261454017643500241210ustar00rootroot00000000000000{ "child1": "Alex", "child2": "Julia", "child3": "Michael", "child4": "Natalie" } koanf-providers-vault-v2.0.1/examples/default-values/000077500000000000000000000000001454017643500227125ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/default-values/main.go000066400000000000000000000021401454017643500241620ustar00rootroot00000000000000package main import ( "fmt" "log" "github.com/knadh/koanf/v2" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/providers/file" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Load default values using the confmap provider. // We provide a flat map with the "." delimiter. // A nested map can be loaded by setting the delimiter to an empty string "". k.Load(confmap.Provider(map[string]interface{}{ "parent1.name": "Default Name", "parent3.name": "New name here", }, "."), nil) // Load JSON config on top of the default values. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load YAML config and merge into the previously loaded config (because we can). k.Load(file.Provider("mock/mock.yml"), yaml.Parser()) fmt.Println("parent's name is = ", k.String("parent1.name")) fmt.Println("parent's ID is = ", k.Int("parent1.id")) } koanf-providers-vault-v2.0.1/examples/go.mod000066400000000000000000000000001454017643500210650ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-appconfig/000077500000000000000000000000001454017643500226505ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-appconfig/main.go000066400000000000000000000022261454017643500241250ustar00rootroot00000000000000package main import ( "log" "os" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/appconfig/v2" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { provider, err := appconfig.Provider(appconfig.Config{ Application: os.Getenv("AWS_APPCONFIG_APPLICATION"), ClientID: os.Getenv("AWS_APPCONFIG_CLIENT_ID"), Configuration: os.Getenv("AWS_APPCONFIG_CONFIG_NAME"), Environment: os.Getenv("AWS_APPCONFIG_ENVIRONMENT"), }) if err != nil { log.Fatalf("Failed to instantiate appconfig provider: %v", err) } // Load the provider and parse configuration as JSON. if err := k.Load(provider, json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } k.Print() // Watch for all configuration updates. provider.Watch(func(event interface{}, err error) { if err != nil { log.Printf("watch error: %v", err) return } log.Println("config changed. Reloading ...") k = koanf.New(".") k.Load(provider, json.Parser()) k.Print() }) log.Println("waiting forever.") <-make(chan bool) } koanf-providers-vault-v2.0.1/examples/read-commandline/000077500000000000000000000000001454017643500231705ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-commandline/main.go000066400000000000000000000031421454017643500244430ustar00rootroot00000000000000package main import ( "fmt" "log" "os" "github.com/knadh/koanf/parsers/toml" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/posflag" "github.com/knadh/koanf/v2" flag "github.com/spf13/pflag" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Use the POSIX compliant pflag lib instead of Go's flag lib. f := flag.NewFlagSet("config", flag.ContinueOnError) f.Usage = func() { fmt.Println(f.FlagUsages()) os.Exit(0) } // Path to one or more config files to load into koanf along with some config params. f.StringSlice("conf", []string{"mock/mock.toml"}, "path to one or more .toml config files") f.String("time", "2020-01-01", "a time string") f.String("type", "xxx", "type of the app") f.Parse(os.Args[1:]) // Load the config files provided in the commandline. cFiles, _ := f.GetStringSlice("conf") for _, c := range cFiles { if err := k.Load(file.Provider(c), toml.Parser()); err != nil { log.Fatalf("error loading file: %v", err) } } // "time" and "type" may have been loaded from the config file, but // they can still be overridden with the values from the command line. // The bundled posflag.Provider takes a flagset from the spf13/pflag lib. // Passing the Koanf instance to posflag helps it deal with default command // line flag values that are not present in conf maps from previously loaded // providers. if err := k.Load(posflag.Provider(f, ".", k), nil); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println("time is = ", k.String("time")) } koanf-providers-vault-v2.0.1/examples/read-consul/000077500000000000000000000000001454017643500222055ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-consul/data.json000066400000000000000000000002531454017643500240110ustar00rootroot00000000000000{ "parent1": "father", "parent2": "mother", "child1": "Alex", "child2": "Julia", "child3": "Michael", "child4": "Natalie", "child5": "Rosalind", "child6": "Tim" } koanf-providers-vault-v2.0.1/examples/read-consul/koanfconsul.sh000077500000000000000000000005541454017643500250720ustar00rootroot00000000000000consul agent -dev & exitcode=1 iterations=0 while [ $exitcode -ne 0 ] do consul members exitcode=$? sleep 1 ((iterations++)) if [ $iterations -gt 5 ]; then break fi done if [ $exitcode -eq 0 ]; then echo -e "\nTest program running..." go run main.go echo -e "\nShutdown..." consul leave else echo "Consul server is inavailable." consul leave fi koanf-providers-vault-v2.0.1/examples/read-consul/main.go000066400000000000000000000157161454017643500234720ustar00rootroot00000000000000package main import ( "fmt" "log" "os/exec" "strings" "github.com/hashicorp/consul/api" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/consul/v2" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" ) var ( kData = koanf.New(".") kReq = koanf.New(".") kCheck = koanf.New(".") ) func main() { if err := kData.Load(file.Provider("data.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } cli, err := api.NewClient(api.DefaultConfig()) if err != nil { log.Fatalf("error creating client: %v", err) } kv := cli.KV() keysData := kData.Keys() for _, key := range keysData { newPair := &api.KVPair{Key: key, Value: []byte(kData.String(key))} _, err = kv.Put(newPair, nil) if err != nil { log.Printf("Couldn't put key.") } } // Single key/value. var ( sKey string = "single_key" sVal string = "single_val" ) newPair := &api.KVPair{Key: sKey, Value: []byte(sVal)} _, err = kv.Put(newPair, nil) if err != nil { log.Printf("Couldn't put key.") } provider, err := consul.Provider(consul.Config{ Key: sKey, Recurse: false, Detailed: false, Cfg: api.DefaultConfig(), }) if err != nil { log.Fatalf("Failed to instantiate consul provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } if len(kCheck.Keys()) != 1 { fmt.Printf("Single key: FAILED\n") return } if strings.Compare(sKey, kCheck.Keys()[0]) != 0 { fmt.Printf("Single key: key comparison FAILED\n") return } if strings.Compare(sVal, kCheck.String(kCheck.Keys()[0])) != 0 { fmt.Printf("Single key: value comparison FAILED\n") return } fmt.Printf("\nSingle key test passed.\n") kCheck.Delete("") // first request test // analog of the command: // consul kv get -recurse parent if err := kReq.Load(file.Provider("req1.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } provider, err = consul.Provider(consul.Config{ Key: "parent", Recurse: true, Detailed: false, Cfg: api.DefaultConfig(), }) if err != nil { log.Fatalf("Failed to instantiate consul provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } keysReq := kReq.Keys() keysCheck := kCheck.Keys() if len(keysReq) != len(keysCheck) { fmt.Printf("First request: keys FAILED\n") return } for i := 0; i < len(keysReq); i++ { if strings.Compare(keysReq[i], keysCheck[i]) != 0 { fmt.Printf("First request: key comparison FAILED\n") return } if strings.Compare(kReq.String(keysReq[i]), kCheck.String(keysCheck[i])) != 0 { fmt.Printf("First request: value comparison FAILED\n") return } } fmt.Printf("First request test passed.\n") kReq.Delete("") kCheck.Delete("") // second request test // analog of the command: // consul kv get -recurse child if err := kReq.Load(file.Provider("req2.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } provider, err = consul.Provider(consul.Config{ Key: "child", Recurse: true, Detailed: false, Cfg: api.DefaultConfig(), }) if err != nil { log.Fatalf("Failed to instantiate consul provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } keysReq = kReq.Keys() keysCheck = kCheck.Keys() if len(keysReq) != len(keysCheck) { fmt.Printf("Second request: keys FAILED\n") return } for i := 0; i < len(keysReq); i++ { if strings.Compare(keysReq[i], keysCheck[i]) != 0 { } if strings.Compare(kReq.String(keysReq[i]), kCheck.String(keysCheck[i])) != 0 { fmt.Printf("Second request: value comparison FAILED\n") return } } fmt.Printf("Second request test passed.\n") kCheck.Delete("") // adding metainformation: age (flags) newPair = &api.KVPair{Key: "parent1", Flags: uint64(42), Value: []byte("father")} _, err = kv.Put(newPair, nil) if err != nil { log.Printf("Couldn't put key with flags.") } // Single key detailed test. // analog of the command: // consul kv get -detailed parent1 sKey = "parent1" sFlags := uint64(42) sVal = "father" provider, err = consul.Provider(consul.Config{ Key: sKey, Recurse: false, Detailed: true, Cfg: api.DefaultConfig(), }) if err != nil { log.Fatalf("Failed to instantiate consul provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { fmt.Printf("error loading config: %v", err) return } if sFlags != uint64(kCheck.Int64("parent1.Flags")) { fmt.Printf("Single detailed key: flags (metadata: age) comparison FAILED\n") return } if strings.Compare(sVal, kCheck.String("parent1.Value")) != 0 { fmt.Printf("Single detailed key: value comparison FAILED\n") return } fmt.Printf("\nDetailed single key test passed.\n") kCheck.Delete("") // Detailed request (recurse) test. // analog of the command: // consul kv get -detailed -recurse parent sKey = "parent" provider, err = consul.Provider(consul.Config{ Key: sKey, Recurse: true, Detailed: true, Cfg: api.DefaultConfig(), }) if err != nil { log.Fatalf("Failed to instantiate consul provider: %v", err) } if err := kCheck.Load(provider, nil); err != nil { fmt.Printf("error loading config: %v", err) return } if sFlags != uint64(kCheck.Int64("parent1.Flags")) { fmt.Printf("Single detailed key: flags (metadata: age) comparison FAILED\n") return } if strings.Compare(sVal, kCheck.String("parent1.Value")) != 0 { fmt.Printf("Single key: value comparison FAILED\n") return } sFlags = uint64(0) sVal = "mother" if sFlags != uint64(kCheck.Int64("parent2.Flags")) { fmt.Printf("Single detailed key: flags (metadata: age) comparison FAILED\n") return } if strings.Compare(sVal, kCheck.String("parent2.Value")) != 0 { fmt.Printf("Single key: value comparison FAILED\n") return } fmt.Printf("\nDetailed request (recurse) test passed.\n") kCheck.Delete("") // Watch test sKey = "parent" provider, err = consul.Provider(consul.Config{ Key: sKey, Recurse: true, Detailed: false, Cfg: api.DefaultConfig(), }) if err != nil { log.Fatalf("Failed to instantiate consul provider: %v", err) } // Getting the old value kCheck.Load(provider, nil) oldVal := kCheck.String("parent1") changedC := make(chan string, 1) provider.Watch(func(event interface{}, err error) { if err != nil { fmt.Printf("Unexpected error: %v", err) return } kCheck.Load(provider, nil) // skip the first call if strings.Compare(oldVal, kCheck.String("parent1")) != 0 { changedC <- kCheck.String("parent1") } }) // changing var newVal string = "dad" cmd := exec.Command("consul", "kv", "put", "parent1", newVal) err = cmd.Run() if err != nil { log.Fatal(err) } if strings.Compare(newVal, <-changedC) != 0 { fmt.Printf("Watch failed: new value comparison FAILED\n") return } fmt.Printf("Watch test passed.\n") fmt.Printf("ALL TESTS PASSED\n") } koanf-providers-vault-v2.0.1/examples/read-consul/req1.json000066400000000000000000000000571454017643500237520ustar00rootroot00000000000000{ "parent1": "father", "parent2": "mother" } koanf-providers-vault-v2.0.1/examples/read-consul/req2.json000066400000000000000000000001771454017643500237560ustar00rootroot00000000000000{ "child1": "Alex", "child2": "Julia", "child3": "Michael", "child4": "Natalie", "child5": "Rosalind", "child6": "Tim" } koanf-providers-vault-v2.0.1/examples/read-environment/000077500000000000000000000000001454017643500232465ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-environment/main.go000066400000000000000000000036621454017643500245300ustar00rootroot00000000000000package main import ( "fmt" "log" "strings" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" ) var k = koanf.New(".") func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load environment variables and merge into the loaded config. // "MYVAR" is the prefix to filter the env vars by. // "." is the delimiter used to represent the key hierarchy in env vars. // The (optional, or can be nil) function can be used to transform // the env var names, for instance, to lowercase them. // // For example, env vars: MYVAR_TYPE and MYVAR_PARENT1_CHILD1_NAME // will be merged into the "type" and the nested "parent1.child1.name" // keys in the config file here as we lowercase the key, // replace `_` with `.` and strip the MYVAR_ prefix so that // only "parent1.child1.name" remains. k.Load(env.Provider("MYVAR_", ".", func(s string) string { return strings.Replace(strings.ToLower( strings.TrimPrefix(s, "MYVAR_")), "_", ".", -1) }), nil) // Use ProviderWithValue() to process both keys and values into types other than strings, // for example, turn space separated env vars into slices. // k.Load(env.ProviderWithValue("MYVAR_", ".", func(s string, v string) (string, interface{}) { // // Strip out the MYVAR_ prefix and lowercase and get the key while also replacing // // the _ character with . in the key (koanf delimeter). // key := strings.Replace(strings.ToLower(strings.TrimPrefix(s, "MYVAR_")), "_", ".", -1) // // If there is a space in the value, split the value into a slice by the space. // if strings.Contains(v, " ") { // return key, strings.Split(v, " ") // } // // Otherwise, return the plain string. // return key, v // }), nil) fmt.Println("name is = ", k.String("parent1.child1.name")) } koanf-providers-vault-v2.0.1/examples/read-file/000077500000000000000000000000001454017643500216215ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-file/main.go000066400000000000000000000024341454017643500230770ustar00rootroot00000000000000package main import ( "fmt" "log" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Load JSON config. f := file.Provider("mock/mock.json") if err := k.Load(f, json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } // Load YAML config and merge into the previously loaded config (because we can). k.Load(file.Provider("mock/mock.yml"), yaml.Parser()) fmt.Println("parent's name is = ", k.String("parent1.name")) fmt.Println("parent's ID is = ", k.Int("parent1.id")) // Watch the file and get a callback on change. The callback can do whatever, // like re-load the configuration. // File provider always returns a nil `event`. f.Watch(func(event interface{}, err error) { if err != nil { log.Printf("watch error: %v", err) return } log.Println("config changed. Reloading ...") k.Load(f, json.Parser()) k.Print() }) // Block forever (and manually make a change to mock/mock.json) to // reload the config. log.Println("waiting forever. Try making a change to mock/mock.json to live reload") <-make(chan bool) } koanf-providers-vault-v2.0.1/examples/read-parameterstore/000077500000000000000000000000001454017643500237375ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-parameterstore/README.md000066400000000000000000000002211454017643500252110ustar00rootroot00000000000000# AWS Parameter Store Example ## Link [another example](https://github.com/defensestation/koanf/blob/main/examples/read-parameterstore/main.go) koanf-providers-vault-v2.0.1/examples/read-parameterstore/main.go000066400000000000000000000037021454017643500252140ustar00rootroot00000000000000package main import ( "context" "fmt" "log" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/knadh/koanf/providers/parameterstore/v2" "github.com/knadh/koanf/v2" ) var k = koanf.New(".") func main() { // The configuration values are read from the environment variables. c, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatal(err) } client := ssm.NewFromConfig(c) for k, v := range map[string]string{ "parent1": "alice", "parent2.child1": "bob", "parent2.child2.grandchild1": "carol", } { if _, err := client.PutParameter(context.TODO(), &ssm.PutParameterInput{ Name: aws.String(k), Value: aws.String(v), Type: types.ParameterTypeSecureString, Overwrite: aws.Bool(true), }); err != nil { log.Fatal(err) } } // Get a parameter. if err := k.Load(parameterstore.ProviderWithClient(parameterstore.Config[ssm.GetParameterInput]{ Delim: ".", Input: ssm.GetParameterInput{Name: aws.String("parent1"), WithDecryption: aws.Bool(true)}, }, client), nil); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println(k.Sprint()) // Get parameters. if err := k.Load(parameterstore.ProviderWithClient(parameterstore.Config[ssm.GetParametersInput]{ Delim: ".", Input: ssm.GetParametersInput{Names: []string{"parent1", "parent2.child1"}, WithDecryption: aws.Bool(true)}, }, client), nil); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println(k.Sprint()) // Get parameters by path. if err := k.Load(parameterstore.ProviderWithClient(parameterstore.Config[ssm.GetParametersByPathInput]{ Delim: ".", Input: ssm.GetParametersByPathInput{Path: aws.String("/"), WithDecryption: aws.Bool(true)}, }, client), nil); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println(k.Sprint()) } koanf-providers-vault-v2.0.1/examples/read-raw-bytes/000077500000000000000000000000001454017643500226175ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-raw-bytes/main.go000066400000000000000000000007141454017643500240740ustar00rootroot00000000000000package main import ( "fmt" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/rawbytes" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var k = koanf.New(".") func main() { b := []byte(`{"type": "rawbytes", "parent1": {"child1": {"type": "rawbytes"}}}`) k.Load(rawbytes.Provider(b), json.Parser()) fmt.Println("type is = ", k.String("parent1.child1.type")) } koanf-providers-vault-v2.0.1/examples/read-s3/000077500000000000000000000000001454017643500212275ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-s3/main.go000066400000000000000000000013741454017643500225070ustar00rootroot00000000000000package main import ( "fmt" "log" "os" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/s3" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { // Load JSON config from s3. if err := k.Load(s3.Provider(s3.Config{ AccessKey: os.Getenv("AWS_S3_ACCESS_KEY"), SecretKey: os.Getenv("AWS_S3_SECRET_KEY"), Region: os.Getenv("AWS_S3_REGION"), Bucket: os.Getenv("AWS_S3_BUCKET"), ObjectKey: "mock/mock.json", }), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println("parent's name is = ", k.String("parent1.name")) fmt.Println("parent's ID is = ", k.Int("parent1.id")) } koanf-providers-vault-v2.0.1/examples/read-secretsmanager/000077500000000000000000000000001454017643500237055ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-secretsmanager/README.md000066400000000000000000000002101454017643500251550ustar00rootroot00000000000000# AWS Secrets Manager Example ## Link [example](https://github.com/defensestation/koanf/blob/main/examples/read-secretsmanager/main.go)koanf-providers-vault-v2.0.1/examples/read-struct/000077500000000000000000000000001454017643500222265ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-struct/main.go000066400000000000000000000022361454017643500235040ustar00rootroot00000000000000package main import ( "fmt" "github.com/knadh/koanf/providers/structs" "github.com/knadh/koanf/v2" ) var k = koanf.New(".") type parentStruct struct { Name string `koanf:"name"` ID int `koanf:"id"` Child1 childStruct `koanf:"child1"` } type childStruct struct { Name string `koanf:"name"` Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Grandchild1 grandchildStruct `koanf:"grandchild1"` } type grandchildStruct struct { Ids []int `koanf:"ids"` On bool `koanf:"on"` } type sampleStruct struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1 parentStruct `koanf:"parent1"` } func main() { s := sampleStruct{ Type: "json", Empty: make(map[string]string), Parent1: parentStruct{ Name: "parent1", ID: 1234, Child1: childStruct{ Name: "child1", Type: "json", Empty: make(map[string]string), Grandchild1: grandchildStruct{ Ids: []int{1, 2, 3}, On: true, }, }, }, } k.Load(structs.Provider(s, "koanf"), nil) fmt.Printf("name is = `%s`\n", k.String("parent1.child1.name")) } koanf-providers-vault-v2.0.1/examples/read-vault/000077500000000000000000000000001454017643500220355ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/read-vault/main.go000066400000000000000000000017671454017643500233230ustar00rootroot00000000000000package main import ( "fmt" "log" "os" "time" "github.com/knadh/koanf/providers/vault/v2" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character. var k = koanf.New(".") func main() { provider, err := vault.Provider(vault.Config{ Address: os.Getenv("VAULT_ADDRESS"), Token: os.Getenv("VAULT_TOKEN"), Path: "secret/data/my-app", Timeout: 10 * time.Second, // If this is set to false, then `data` and `metadata` keys // from Vault are fetched. All config is then accessed as // k.String("data.YOUR_KEY") etc. instead of k.String("YOUR_KEY"). ExcludeMeta: true, }) if err != nil { log.Fatalf("Failed to instantiate vault provider: %v", err) } // Load mapped config from Vault storage. if err := k.Load(provider, nil); err != nil { log.Fatalf("error loading config: %v", err) } fmt.Println("database's host is = ", k.String("database.host")) fmt.Println("database's port is = ", k.Int("database.port")) } koanf-providers-vault-v2.0.1/examples/unmarshal-flat/000077500000000000000000000000001454017643500227075ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/unmarshal-flat/main.go000066400000000000000000000036311454017643500241650ustar00rootroot00000000000000package main import ( "fmt" "log" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var k = koanf.New(".") func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil { log.Fatalf("error loading config: %v", err) } type rootFlat struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1Name string `koanf:"parent1.name"` Parent1ID int `koanf:"parent1.id"` Parent1Child1Name string `koanf:"parent1.child1.name"` Parent1Child1Type string `koanf:"parent1.child1.type"` Parent1Child1Empty map[string]string `koanf:"parent1.child1.empty"` Parent1Child1Grandchild1IDs []int `koanf:"parent1.child1.grandchild1.ids"` Parent1Child1Grandchild1On bool `koanf:"parent1.child1.grandchild1.on"` } // Unmarshal the whole root with FlatPaths: True. var o1 rootFlat k.UnmarshalWithConf("", &o1, koanf.UnmarshalConf{Tag: "koanf", FlatPaths: true}) fmt.Println(o1) // Unmarshal a child structure of "parent1". type subFlat struct { Name string `koanf:"name"` ID int `koanf:"id"` Child1Name string `koanf:"child1.name"` Child1Type string `koanf:"child1.type"` Child1Empty map[string]string `koanf:"child1.empty"` Child1Grandchild1IDs []int `koanf:"child1.grandchild1.ids"` Child1Grandchild1On bool `koanf:"child1.grandchild1.on"` } var o2 subFlat k.UnmarshalWithConf("parent1", &o2, koanf.UnmarshalConf{Tag: "koanf", FlatPaths: true}) fmt.Println(o2) } koanf-providers-vault-v2.0.1/examples/unmarshal/000077500000000000000000000000001454017643500217635ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/examples/unmarshal/main.go000066400000000000000000000022531454017643500232400ustar00rootroot00000000000000package main import ( "fmt" "log" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" ) // Global koanf instance. Use . as the key path delimiter. This can be / or anything. var ( k = koanf.New(".") parser = json.Parser() ) func main() { // Load JSON config. if err := k.Load(file.Provider("mock/mock.json"), parser); err != nil { log.Fatalf("error loading config: %v", err) } // Structure to unmarshal nested conf to. type childStruct struct { Name string `koanf:"name"` Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` GrandChild struct { Ids []int `koanf:"ids"` On bool `koanf:"on"` } `koanf:"grandchild1"` } var out childStruct // Quick unmarshal. k.Unmarshal("parent1.child1", &out) fmt.Println(out) // Unmarshal with advanced config. out = childStruct{} k.UnmarshalWithConf("parent1.child1", &out, koanf.UnmarshalConf{Tag: "koanf"}) fmt.Println(out) // Marshal the instance back to JSON. // The paser instance can be anything, eg: json.Paser(), // yaml.Parser() etc. b, _ := k.Marshal(parser) fmt.Println(string(b)) } koanf-providers-vault-v2.0.1/getters.go000066400000000000000000000364521454017643500201710ustar00rootroot00000000000000package koanf import ( "fmt" "time" ) // Int64 returns the int64 value of a given key path or 0 if the path // does not exist or if the value is not a valid int64. func (ko *Koanf) Int64(path string) int64 { if v := ko.Get(path); v != nil { i, _ := toInt64(v) return i } return 0 } // MustInt64 returns the int64 value of a given key path or panics // if the value is not set or set to default value of 0. func (ko *Koanf) MustInt64(path string) int64 { val := ko.Int64(path) if val == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Int64s returns the []int64 slice value of a given key path or an // empty []int64 slice if the path does not exist or if the value // is not a valid int slice. func (ko *Koanf) Int64s(path string) []int64 { o := ko.Get(path) if o == nil { return []int64{} } var out []int64 switch v := o.(type) { case []int64: return v case []int: out = make([]int64, 0, len(v)) for _, vi := range v { i, err := toInt64(vi) // On error, return as it's not a valid // int slice. if err != nil { return []int64{} } out = append(out, i) } return out case []interface{}: out = make([]int64, 0, len(v)) for _, vi := range v { i, err := toInt64(vi) // On error, return as it's not a valid // int slice. if err != nil { return []int64{} } out = append(out, i) } return out } return []int64{} } // MustInt64s returns the []int64 slice value of a given key path or panics // if the value is not set or its default value. func (ko *Koanf) MustInt64s(path string) []int64 { val := ko.Int64s(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Int64Map returns the map[string]int64 value of a given key path // or an empty map[string]int64 if the path does not exist or if the // value is not a valid int64 map. func (ko *Koanf) Int64Map(path string) map[string]int64 { var ( out = map[string]int64{} o = ko.Get(path) ) if o == nil { return out } mp, ok := o.(map[string]interface{}) if !ok { return out } out = make(map[string]int64, len(mp)) for k, v := range mp { switch i := v.(type) { case int64: out[k] = i default: // Attempt a conversion. iv, err := toInt64(i) if err != nil { return map[string]int64{} } out[k] = iv } } return out } // MustInt64Map returns the map[string]int64 value of a given key path // or panics if it isn't set or set to default value. func (ko *Koanf) MustInt64Map(path string) map[string]int64 { val := ko.Int64Map(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Int returns the int value of a given key path or 0 if the path // does not exist or if the value is not a valid int. func (ko *Koanf) Int(path string) int { return int(ko.Int64(path)) } // MustInt returns the int value of a given key path or panics // if it isn't set or set to default value of 0. func (ko *Koanf) MustInt(path string) int { val := ko.Int(path) if val == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Ints returns the []int slice value of a given key path or an // empty []int slice if the path does not exist or if the value // is not a valid int slice. func (ko *Koanf) Ints(path string) []int { o := ko.Get(path) if o == nil { return []int{} } var out []int switch v := o.(type) { case []int: return v case []int64: out = make([]int, 0, len(v)) for _, vi := range v { out = append(out, int(vi)) } return out case []interface{}: out = make([]int, 0, len(v)) for _, vi := range v { i, err := toInt64(vi) // On error, return as it's not a valid // int slice. if err != nil { return []int{} } out = append(out, int(i)) } return out } return []int{} } // MustInts returns the []int slice value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustInts(path string) []int { val := ko.Ints(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // IntMap returns the map[string]int value of a given key path // or an empty map[string]int if the path does not exist or if the // value is not a valid int map. func (ko *Koanf) IntMap(path string) map[string]int { var ( mp = ko.Int64Map(path) out = make(map[string]int, len(mp)) ) for k, v := range mp { out[k] = int(v) } return out } // MustIntMap returns the map[string]int value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustIntMap(path string) map[string]int { val := ko.IntMap(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Float64 returns the float64 value of a given key path or 0 if the path // does not exist or if the value is not a valid float64. func (ko *Koanf) Float64(path string) float64 { if v := ko.Get(path); v != nil { f, _ := toFloat64(v) return f } return 0 } // MustFloat64 returns the float64 value of a given key path or panics // if it isn't set or set to default value 0. func (ko *Koanf) MustFloat64(path string) float64 { val := ko.Float64(path) if val == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Float64s returns the []float64 slice value of a given key path or an // empty []float64 slice if the path does not exist or if the value // is not a valid float64 slice. func (ko *Koanf) Float64s(path string) []float64 { o := ko.Get(path) if o == nil { return []float64{} } var out []float64 switch v := o.(type) { case []float64: return v case []interface{}: out = make([]float64, 0, len(v)) for _, vi := range v { i, err := toFloat64(vi) // On error, return as it's not a valid // int slice. if err != nil { return []float64{} } out = append(out, i) } return out } return []float64{} } // MustFloat64s returns the []Float64 slice value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustFloat64s(path string) []float64 { val := ko.Float64s(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Float64Map returns the map[string]float64 value of a given key path // or an empty map[string]float64 if the path does not exist or if the // value is not a valid float64 map. func (ko *Koanf) Float64Map(path string) map[string]float64 { var ( out = map[string]float64{} o = ko.Get(path) ) if o == nil { return out } mp, ok := o.(map[string]interface{}) if !ok { return out } out = make(map[string]float64, len(mp)) for k, v := range mp { switch i := v.(type) { case float64: out[k] = i default: // Attempt a conversion. iv, err := toFloat64(i) if err != nil { return map[string]float64{} } out[k] = iv } } return out } // MustFloat64Map returns the map[string]float64 value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustFloat64Map(path string) map[string]float64 { val := ko.Float64Map(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Duration returns the time.Duration value of a given key path assuming // that the key contains a valid numeric value. func (ko *Koanf) Duration(path string) time.Duration { // Look for a parsable string representation first. if v := ko.Int64(path); v != 0 { return time.Duration(v) } v, _ := time.ParseDuration(ko.String(path)) return v } // MustDuration returns the time.Duration value of a given key path or panics // if it isn't set or set to default value 0. func (ko *Koanf) MustDuration(path string) time.Duration { val := ko.Duration(path) if val == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Time attempts to parse the value of a given key path and return time.Time // representation. If the value is numeric, it is treated as a UNIX timestamp // and if it's string, a parse is attempted with the given layout. func (ko *Koanf) Time(path, layout string) time.Time { // Unix timestamp? v := ko.Int64(path) if v != 0 { return time.Unix(v, 0) } // String representation. s := ko.String(path) if s != "" { t, _ := time.Parse(layout, s) return t } return time.Time{} } // MustTime attempts to parse the value of a given key path and return time.Time // representation. If the value is numeric, it is treated as a UNIX timestamp // and if it's string, a parse is attempted with the given layout. It panics if // the parsed time is zero. func (ko *Koanf) MustTime(path, layout string) time.Time { val := ko.Time(path, layout) if val.IsZero() { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // String returns the string value of a given key path or "" if the path // does not exist or if the value is not a valid string. func (ko *Koanf) String(path string) string { if v := ko.Get(path); v != nil { if i, ok := v.(string); ok { return i } return fmt.Sprintf("%v", v) } return "" } // MustString returns the string value of a given key path // or panics if it isn't set or set to default value "". func (ko *Koanf) MustString(path string) string { val := ko.String(path) if val == "" { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Strings returns the []string slice value of a given key path or an // empty []string slice if the path does not exist or if the value // is not a valid string slice. func (ko *Koanf) Strings(path string) []string { o := ko.Get(path) if o == nil { return []string{} } var out []string switch v := o.(type) { case []interface{}: out = make([]string, 0, len(v)) for _, u := range v { if s, ok := u.(string); ok { out = append(out, s) } else { out = append(out, fmt.Sprintf("%v", u)) } } return out case []string: out := make([]string, len(v)) copy(out, v) return out } return []string{} } // MustStrings returns the []string slice value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustStrings(path string) []string { val := ko.Strings(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // StringMap returns the map[string]string value of a given key path // or an empty map[string]string if the path does not exist or if the // value is not a valid string map. func (ko *Koanf) StringMap(path string) map[string]string { var ( out = map[string]string{} o = ko.Get(path) ) if o == nil { return out } switch mp := o.(type) { case map[string]string: out = make(map[string]string, len(mp)) for k, v := range mp { out[k] = v } case map[string]interface{}: out = make(map[string]string, len(mp)) for k, v := range mp { switch s := v.(type) { case string: out[k] = s default: // There's a non string type. Return. return map[string]string{} } } } return out } // MustStringMap returns the map[string]string value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustStringMap(path string) map[string]string { val := ko.StringMap(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // StringsMap returns the map[string][]string value of a given key path // or an empty map[string][]string if the path does not exist or if the // value is not a valid strings map. func (ko *Koanf) StringsMap(path string) map[string][]string { var ( out = map[string][]string{} o = ko.Get(path) ) if o == nil { return out } switch mp := o.(type) { case map[string][]string: out = make(map[string][]string, len(mp)) for k, v := range mp { out[k] = append(out[k], v...) } case map[string][]interface{}: out = make(map[string][]string, len(mp)) for k, v := range mp { for _, v := range v { switch sv := v.(type) { case string: out[k] = append(out[k], sv) default: return map[string][]string{} } } } case map[string]interface{}: out = make(map[string][]string, len(mp)) for k, v := range mp { switch s := v.(type) { case []string: out[k] = append(out[k], s...) case []interface{}: for _, v := range s { switch sv := v.(type) { case string: out[k] = append(out[k], sv) default: return map[string][]string{} } } default: // There's a non []interface type. Return. return map[string][]string{} } } } return out } // MustStringsMap returns the map[string][]string value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustStringsMap(path string) map[string][]string { val := ko.StringsMap(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Bytes returns the []byte value of a given key path or an empty // []byte slice if the path does not exist or if the value is not a valid string. func (ko *Koanf) Bytes(path string) []byte { return []byte(ko.String(path)) } // MustBytes returns the []byte value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustBytes(path string) []byte { val := ko.Bytes(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // Bool returns the bool value of a given key path or false if the path // does not exist or if the value is not a valid bool representation. // Accepted string representations of bool are the ones supported by strconv.ParseBool. func (ko *Koanf) Bool(path string) bool { if v := ko.Get(path); v != nil { b, _ := toBool(v) return b } return false } // Bools returns the []bool slice value of a given key path or an // empty []bool slice if the path does not exist or if the value // is not a valid bool slice. func (ko *Koanf) Bools(path string) []bool { o := ko.Get(path) if o == nil { return []bool{} } var out []bool switch v := o.(type) { case []interface{}: out = make([]bool, 0, len(v)) for _, u := range v { b, err := toBool(u) if err != nil { return nil } out = append(out, b) } return out case []bool: return out } return nil } // MustBools returns the []bool value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustBools(path string) []bool { val := ko.Bools(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } // BoolMap returns the map[string]bool value of a given key path // or an empty map[string]bool if the path does not exist or if the // value is not a valid bool map. func (ko *Koanf) BoolMap(path string) map[string]bool { var ( out = map[string]bool{} o = ko.Get(path) ) if o == nil { return out } mp, ok := o.(map[string]interface{}) if !ok { return out } out = make(map[string]bool, len(mp)) for k, v := range mp { switch i := v.(type) { case bool: out[k] = i default: // Attempt a conversion. b, err := toBool(i) if err != nil { return map[string]bool{} } out[k] = b } } return out } // MustBoolMap returns the map[string]bool value of a given key path or panics // if the value is not set or set to default value. func (ko *Koanf) MustBoolMap(path string) map[string]bool { val := ko.BoolMap(path) if len(val) == 0 { panic(fmt.Sprintf("invalid value: %s=%v", path, val)) } return val } koanf-providers-vault-v2.0.1/go.mod000066400000000000000000000003551454017643500172640ustar00rootroot00000000000000module github.com/knadh/koanf/v2 go 1.18 require ( github.com/knadh/koanf/maps v0.1.1 github.com/mitchellh/copystructure v1.2.0 github.com/mitchellh/mapstructure v1.5.0 ) require github.com/mitchellh/reflectwalk v1.0.2 // indirect koanf-providers-vault-v2.0.1/go.sum000066400000000000000000000013301454017643500173030ustar00rootroot00000000000000github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= koanf-providers-vault-v2.0.1/go.work000066400000000000000000000000351454017643500174620ustar00rootroot00000000000000go 1.18 use ( . ./tests ) koanf-providers-vault-v2.0.1/interfaces.go000066400000000000000000000013451454017643500206300ustar00rootroot00000000000000package koanf // Provider represents a configuration provider. Providers can // read configuration from a source (file, HTTP etc.) type Provider interface { // ReadBytes returns the entire configuration as raw []bytes to be parsed. // with a Parser. ReadBytes() ([]byte, error) // Read returns the parsed configuration as a nested map[string]interface{}. // It is important to note that the string keys should not be flat delimited // keys like `parent.child.key`, but nested like `{parent: {child: {key: 1}}}`. Read() (map[string]interface{}, error) } // Parser represents a configuration format parser. type Parser interface { Unmarshal([]byte) (map[string]interface{}, error) Marshal(map[string]interface{}) ([]byte, error) } koanf-providers-vault-v2.0.1/koanf.go000066400000000000000000000366371454017643500176170ustar00rootroot00000000000000package koanf import ( "bytes" "encoding" "fmt" "reflect" "sort" "strconv" "github.com/knadh/koanf/maps" "github.com/mitchellh/copystructure" "github.com/mitchellh/mapstructure" ) // Koanf is the configuration apparatus. type Koanf struct { confMap map[string]interface{} confMapFlat map[string]interface{} keyMap KeyMap conf Conf } // Conf is the Koanf configuration. type Conf struct { // Delim is the delimiter to use // when specifying config key paths, for instance a . for `parent.child.key` // or a / for `parent/child/key`. Delim string // StrictMerge makes the merging behavior strict. // Meaning when loading two files that have the same key, // the first loaded file will define the desired type, and if the second file loads // a different type will cause an error. StrictMerge bool } // KeyMap represents a map of flattened delimited keys and the non-delimited // parts as their slices. For nested keys, the map holds all levels of path combinations. // For example, the nested structure `parent -> child -> key` will produce the map: // parent.child.key => [parent, child, key] // parent.child => [parent, child] // parent => [parent] type KeyMap map[string][]string // UnmarshalConf represents configuration options used by // Unmarshal() to unmarshal conf maps into arbitrary structs. type UnmarshalConf struct { // Tag is the struct field tag to unmarshal. // `koanf` is used if left empty. Tag string // If this is set to true, instead of unmarshalling nested structures // based on the key path, keys are taken literally to unmarshal into // a flat struct. For example: // ``` // type MyStuff struct { // Child1Name string `koanf:"parent1.child1.name"` // Child2Name string `koanf:"parent2.child2.name"` // Type string `koanf:"json"` // } // ``` FlatPaths bool DecoderConfig *mapstructure.DecoderConfig } // New returns a new instance of Koanf. delim is the delimiter to use // when specifying config key paths, for instance a . for `parent.child.key` // or a / for `parent/child/key`. func New(delim string) *Koanf { return NewWithConf(Conf{ Delim: delim, StrictMerge: false, }) } // NewWithConf returns a new instance of Koanf based on the Conf. func NewWithConf(conf Conf) *Koanf { return &Koanf{ confMap: make(map[string]interface{}), confMapFlat: make(map[string]interface{}), keyMap: make(KeyMap), conf: conf, } } // Load takes a Provider that either provides a parsed config map[string]interface{} // in which case pa (Parser) can be nil, or raw bytes to be parsed, where a Parser // can be provided to parse. Additionally, options can be passed which modify the // load behavior, such as passing a custom merge function. func (ko *Koanf) Load(p Provider, pa Parser, opts ...Option) error { var ( mp map[string]interface{} err error ) if p == nil { return fmt.Errorf("load received a nil provider") } // No Parser is given. Call the Provider's Read() method to get // the config map. if pa == nil { mp, err = p.Read() if err != nil { return err } } else { // There's a Parser. Get raw bytes from the Provider to parse. b, err := p.ReadBytes() if err != nil { return err } mp, err = pa.Unmarshal(b) if err != nil { return err } } return ko.merge(mp, newOptions(opts)) } // Keys returns the slice of all flattened keys in the loaded configuration // sorted alphabetically. func (ko *Koanf) Keys() []string { out := make([]string, 0, len(ko.confMapFlat)) for k := range ko.confMapFlat { out = append(out, k) } sort.Strings(out) return out } // KeyMap returns a map of flattened keys and the individual parts of the // key as slices. eg: "parent.child.key" => ["parent", "child", "key"]. func (ko *Koanf) KeyMap() KeyMap { out := make(KeyMap, len(ko.keyMap)) for key, parts := range ko.keyMap { out[key] = make([]string, len(parts)) copy(out[key], parts) } return out } // All returns a map of all flattened key paths and their values. // Note that it uses maps.Copy to create a copy that uses // json.Marshal which changes the numeric types to float64. func (ko *Koanf) All() map[string]interface{} { return maps.Copy(ko.confMapFlat) } // Raw returns a copy of the full raw conf map. // Note that it uses maps.Copy to create a copy that uses // json.Marshal which changes the numeric types to float64. func (ko *Koanf) Raw() map[string]interface{} { return maps.Copy(ko.confMap) } // Sprint returns a key -> value string representation // of the config map with keys sorted alphabetically. func (ko *Koanf) Sprint() string { b := bytes.Buffer{} for _, k := range ko.Keys() { b.WriteString(fmt.Sprintf("%s -> %v\n", k, ko.confMapFlat[k])) } return b.String() } // Print prints a key -> value string representation // of the config map with keys sorted alphabetically. func (ko *Koanf) Print() { fmt.Print(ko.Sprint()) } // Cut cuts the config map at a given key path into a sub map and // returns a new Koanf instance with the cut config map loaded. // For instance, if the loaded config has a path that looks like // parent.child.sub.a.b, `Cut("parent.child")` returns a new Koanf // instance with the config map `sub.a.b` where everything above // `parent.child` are cut out. func (ko *Koanf) Cut(path string) *Koanf { out := make(map[string]interface{}) // Cut only makes sense if the requested key path is a map. if v, ok := ko.Get(path).(map[string]interface{}); ok { out = v } n := New(ko.conf.Delim) _ = n.merge(out, new(options)) return n } // Copy returns a copy of the Koanf instance. func (ko *Koanf) Copy() *Koanf { return ko.Cut("") } // Merge merges the config map of a given Koanf instance into // the current instance. func (ko *Koanf) Merge(in *Koanf) error { return ko.merge(in.Raw(), new(options)) } // MergeAt merges the config map of a given Koanf instance into // the current instance as a sub map, at the given key path. // If all or part of the key path is missing, it will be created. // If the key path is `""`, this is equivalent to Merge. func (ko *Koanf) MergeAt(in *Koanf, path string) error { // No path. Merge the two config maps. if path == "" { return ko.Merge(in) } // Unflatten the config map with the given key path. n := maps.Unflatten(map[string]interface{}{ path: in.Raw(), }, ko.conf.Delim) return ko.merge(n, new(options)) } // Set sets the value at a specific key. func (ko *Koanf) Set(key string, val interface{}) error { // Unflatten the config map with the given key path. n := maps.Unflatten(map[string]interface{}{ key: val, }, ko.conf.Delim) return ko.merge(n, new(options)) } // Marshal takes a Parser implementation and marshals the config map into bytes, // for example, to TOML or JSON bytes. func (ko *Koanf) Marshal(p Parser) ([]byte, error) { return p.Marshal(ko.Raw()) } // Unmarshal unmarshals a given key path into the given struct using // the mapstructure lib. If no path is specified, the whole map is unmarshalled. // `koanf` is the struct field tag used to match field names. To customize, // use UnmarshalWithConf(). It uses the mitchellh/mapstructure package. func (ko *Koanf) Unmarshal(path string, o interface{}) error { return ko.UnmarshalWithConf(path, o, UnmarshalConf{}) } // UnmarshalWithConf is like Unmarshal but takes configuration params in UnmarshalConf. // See mitchellh/mapstructure's DecoderConfig for advanced customization // of the unmarshal behaviour. func (ko *Koanf) UnmarshalWithConf(path string, o interface{}, c UnmarshalConf) error { if c.DecoderConfig == nil { c.DecoderConfig = &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), textUnmarshalerHookFunc()), Metadata: nil, Result: o, WeaklyTypedInput: true, } } if c.Tag == "" { c.DecoderConfig.TagName = "koanf" } else { c.DecoderConfig.TagName = c.Tag } d, err := mapstructure.NewDecoder(c.DecoderConfig) if err != nil { return err } // Unmarshal using flat key paths. mp := ko.Get(path) if c.FlatPaths { if f, ok := mp.(map[string]interface{}); ok { fmp, _ := maps.Flatten(f, nil, ko.conf.Delim) mp = fmp } } return d.Decode(mp) } // Delete removes all nested values from a given path. // Clears all keys/values if no path is specified. // Every empty, key on the path, is recursively deleted. func (ko *Koanf) Delete(path string) { // No path. Erase the entire map. if path == "" { ko.confMap = make(map[string]interface{}) ko.confMapFlat = make(map[string]interface{}) ko.keyMap = make(KeyMap) return } // Does the path exist? p, ok := ko.keyMap[path] if !ok { return } maps.Delete(ko.confMap, p) // Update the flattened version as well. ko.confMapFlat, ko.keyMap = maps.Flatten(ko.confMap, nil, ko.conf.Delim) ko.keyMap = populateKeyParts(ko.keyMap, ko.conf.Delim) } // Get returns the raw, uncast interface{} value of a given key path // in the config map. If the key path does not exist, nil is returned. func (ko *Koanf) Get(path string) interface{} { // No path. Return the whole conf map. if path == "" { return ko.Raw() } // Does the path exist? p, ok := ko.keyMap[path] if !ok { return nil } res := maps.Search(ko.confMap, p) // Non-reference types are okay to return directly. // Other types are "copied" with maps.Copy or json.Marshal // that change the numeric types to float64. switch v := res.(type) { case int, int8, int16, int32, int64, float32, float64, string, bool: return v case map[string]interface{}: return maps.Copy(v) } out, _ := copystructure.Copy(&res) if ptrOut, ok := out.(*interface{}); ok { return *ptrOut } return out } // Slices returns a list of Koanf instances constructed out of a // []map[string]interface{} interface at the given path. func (ko *Koanf) Slices(path string) []*Koanf { out := []*Koanf{} if path == "" { return out } // Does the path exist? sl, ok := ko.Get(path).([]interface{}) if !ok { return out } for _, s := range sl { mp, ok := s.(map[string]interface{}) if !ok { continue } k := New(ko.conf.Delim) _ = k.merge(mp, new(options)) out = append(out, k) } return out } // Exists returns true if the given key path exists in the conf map. func (ko *Koanf) Exists(path string) bool { _, ok := ko.keyMap[path] return ok } // MapKeys returns a sorted string list of keys in a map addressed by the // given path. If the path is not a map, an empty string slice is // returned. func (ko *Koanf) MapKeys(path string) []string { var ( out = []string{} o = ko.Get(path) ) if o == nil { return out } mp, ok := o.(map[string]interface{}) if !ok { return out } out = make([]string, 0, len(mp)) for k := range mp { out = append(out, k) } sort.Strings(out) return out } // Delim returns delimiter in used by this instance of Koanf. func (ko *Koanf) Delim() string { return ko.conf.Delim } func (ko *Koanf) merge(c map[string]interface{}, opts *options) error { maps.IntfaceKeysToStrings(c) if opts.merge != nil { if err := opts.merge(c, ko.confMap); err != nil { return err } } else if ko.conf.StrictMerge { if err := maps.MergeStrict(c, ko.confMap); err != nil { return err } } else { maps.Merge(c, ko.confMap) } // Maintain a flattened version as well. ko.confMapFlat, ko.keyMap = maps.Flatten(ko.confMap, nil, ko.conf.Delim) ko.keyMap = populateKeyParts(ko.keyMap, ko.conf.Delim) return nil } // toInt64 takes an interface value and if it is an integer type, // converts and returns int64. If it's any other type, // forces it to a string and attempts to do a strconv.Atoi // to get an integer out. func toInt64(v interface{}) (int64, error) { switch i := v.(type) { case int: return int64(i), nil case int8: return int64(i), nil case int16: return int64(i), nil case int32: return int64(i), nil case int64: return i, nil } // Force it to a string and try to convert. f, err := strconv.ParseFloat(fmt.Sprintf("%v", v), 64) if err != nil { return 0, err } return int64(f), nil } // toInt64 takes a `v interface{}` value and if it is a float type, // converts and returns a `float64`. If it's any other type, forces it to a // string and attempts to get a float out using `strconv.ParseFloat`. func toFloat64(v interface{}) (float64, error) { switch i := v.(type) { case float32: return float64(i), nil case float64: return i, nil } // Force it to a string and try to convert. f, err := strconv.ParseFloat(fmt.Sprintf("%v", v), 64) if err != nil { return f, err } return f, nil } // toBool takes an interface value and if it is a bool type, // returns it. If it's any other type, forces it to a string and attempts // to parse it as a bool using strconv.ParseBool. func toBool(v interface{}) (bool, error) { if b, ok := v.(bool); ok { return b, nil } // Force it to a string and try to convert. b, err := strconv.ParseBool(fmt.Sprintf("%v", v)) if err != nil { return b, err } return b, nil } // populateKeyParts iterates a key map and generates all possible // traversal paths. For instance, `parent.child.key` generates // `parent`, and `parent.child`. func populateKeyParts(m KeyMap, delim string) KeyMap { out := make(KeyMap, len(m)) // The size of the result is at very least same to KeyMap for _, parts := range m { // parts is a slice of [parent, child, key] var nk string for i := range parts { if i == 0 { // On first iteration only use first part nk = parts[i] } else { // If nk already contains a part (e.g. `parent`) append delim + `child` nk += delim + parts[i] } if _, ok := out[nk]; ok { continue } out[nk] = make([]string, i+1) copy(out[nk], parts[0:i+1]) } } return out } // textUnmarshalerHookFunc is a fixed version of mapstructure.TextUnmarshallerHookFunc. // This hook allows to additionally unmarshal text into custom string types that implement the encoding.Text(Un)Marshaler interface(s). func textUnmarshalerHookFunc() mapstructure.DecodeHookFuncType { return func( f reflect.Type, t reflect.Type, data interface{}, ) (interface{}, error) { if f.Kind() != reflect.String { return data, nil } result := reflect.New(t).Interface() unmarshaller, ok := result.(encoding.TextUnmarshaler) if !ok { return data, nil } // default text representation is the actual value of the `from` string var ( dataVal = reflect.ValueOf(data) text = []byte(dataVal.String()) ) if f.Kind() == t.Kind() { // source and target are of underlying type string var ( err error ptrVal = reflect.New(dataVal.Type()) ) if !ptrVal.Elem().CanSet() { // cannot set, skip, this should not happen if err := unmarshaller.UnmarshalText(text); err != nil { return nil, err } return result, nil } ptrVal.Elem().Set(dataVal) // We need to assert that both, the value type and the pointer type // do (not) implement the TextMarshaller interface before proceeding and simply // using the string value of the string type. // it might be the case that the internal string representation differs from // the (un)marshalled string. for _, v := range []reflect.Value{dataVal, ptrVal} { if marshaller, ok := v.Interface().(encoding.TextMarshaler); ok { text, err = marshaller.MarshalText() if err != nil { return nil, err } break } } } // text is either the source string's value or the source string type's marshaled value // which may differ from its internal string value. if err := unmarshaller.UnmarshalText(text); err != nil { return nil, err } return result, nil } } koanf-providers-vault-v2.0.1/maps/000077500000000000000000000000001454017643500171135ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/maps/go.mod000066400000000000000000000002341454017643500202200ustar00rootroot00000000000000module github.com/knadh/koanf/maps go 1.18 require github.com/mitchellh/copystructure v1.2.0 require github.com/mitchellh/reflectwalk v1.0.2 // indirect koanf-providers-vault-v2.0.1/maps/go.sum000066400000000000000000000005621454017643500202510ustar00rootroot00000000000000github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= koanf-providers-vault-v2.0.1/maps/maps.go000066400000000000000000000210151454017643500204010ustar00rootroot00000000000000// Package maps provides reusable functions for manipulating nested // map[string]interface{} maps are common unmarshal products from // various serializers such as json, yaml etc. package maps import ( "fmt" "reflect" "strings" "github.com/mitchellh/copystructure" ) // Flatten takes a map[string]interface{} and traverses it and flattens // nested children into keys delimited by delim. // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. // // eg: `{ "parent": { "child": 123 }}` becomes `{ "parent.child": 123 }` // In addition, it keeps track of and returns a map of the delimited keypaths with // a slice of key parts, for eg: { "parent.child": ["parent", "child"] }. This // parts list is used to remember the key path's original structure to // unflatten later. func Flatten(m map[string]interface{}, keys []string, delim string) (map[string]interface{}, map[string][]string) { var ( out = make(map[string]interface{}) keyMap = make(map[string][]string) ) flatten(m, keys, delim, out, keyMap) return out, keyMap } func flatten(m map[string]interface{}, keys []string, delim string, out map[string]interface{}, keyMap map[string][]string) { for key, val := range m { // Copy the incoming key paths into a fresh list // and append the current key in the iteration. kp := make([]string, 0, len(keys)+1) kp = append(kp, keys...) kp = append(kp, key) switch cur := val.(type) { case map[string]interface{}: // Empty map. if len(cur) == 0 { newKey := strings.Join(kp, delim) out[newKey] = val keyMap[newKey] = kp continue } // It's a nested map. Flatten it recursively. flatten(cur, kp, delim, out, keyMap) default: newKey := strings.Join(kp, delim) out[newKey] = val keyMap[newKey] = kp } } } // Unflatten takes a flattened key:value map (non-nested with delimited keys) // and returns a nested map where the keys are split into hierarchies by the given // delimiter. For instance, `parent.child.key: 1` to `{parent: {child: {key: 1}}}` // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. func Unflatten(m map[string]interface{}, delim string) map[string]interface{} { out := make(map[string]interface{}) // Iterate through the flat conf map. for k, v := range m { var ( keys = strings.Split(k, delim) next = out ) // Iterate through key parts, for eg:, parent.child.key // will be ["parent", "child", "key"] for _, k := range keys[:len(keys)-1] { sub, ok := next[k] if !ok { // If the key does not exist in the map, create it. sub = make(map[string]interface{}) next[k] = sub } if n, ok := sub.(map[string]interface{}); ok { next = n } } // Assign the value. next[keys[len(keys)-1]] = v } return out } // Merge recursively merges map a into b (left to right), mutating // and expanding map b. Note that there's no copying involved, so // map b will retain references to map a. // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. func Merge(a, b map[string]interface{}) { for key, val := range a { // Does the key exist in the target map? // If no, add it and move on. bVal, ok := b[key] if !ok { b[key] = val continue } // If the incoming val is not a map, do a direct merge. if _, ok := val.(map[string]interface{}); !ok { b[key] = val continue } // The source key and target keys are both maps. Merge them. switch v := bVal.(type) { case map[string]interface{}: Merge(val.(map[string]interface{}), v) default: b[key] = val } } } // MergeStrict recursively merges map a into b (left to right), mutating // and expanding map b. Note that there's no copying involved, so // map b will retain references to map a. // If an equal key in either of the maps has a different value type, it will return the first error. // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. func MergeStrict(a, b map[string]interface{}) error { return mergeStrict(a, b, "") } func mergeStrict(a, b map[string]interface{}, fullKey string) error { for key, val := range a { // Does the key exist in the target map? // If no, add it and move on. bVal, ok := b[key] if !ok { b[key] = val continue } newFullKey := key if fullKey != "" { newFullKey = fmt.Sprintf("%v.%v", fullKey, key) } // If the incoming val is not a map, do a direct merge between the same types. if _, ok := val.(map[string]interface{}); !ok { if reflect.TypeOf(b[key]) == reflect.TypeOf(val) { b[key] = val } else { return fmt.Errorf("incorrect types at key %v, type %T != %T", fullKey, b[key], val) } continue } // The source key and target keys are both maps. Merge them. switch v := bVal.(type) { case map[string]interface{}: if err := mergeStrict(val.(map[string]interface{}), v, newFullKey); err != nil { return err } default: b[key] = val } } return nil } // Delete removes the entry present at a given path, from the map. The path // is the key map slice, for eg:, parent.child.key -> [parent child key]. // Any empty, nested map on the path, is recursively deleted. // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. func Delete(mp map[string]interface{}, path []string) { next, ok := mp[path[0]] if ok { if len(path) == 1 { delete(mp, path[0]) return } switch nval := next.(type) { case map[string]interface{}: Delete(nval, path[1:]) // Delete map if it has no keys. if len(nval) == 0 { delete(mp, path[0]) } } } } // Search recursively searches a map for a given path. The path is // the key map slice, for eg:, parent.child.key -> [parent child key]. // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. func Search(mp map[string]interface{}, path []string) interface{} { next, ok := mp[path[0]] if ok { if len(path) == 1 { return next } switch m := next.(type) { case map[string]interface{}: return Search(m, path[1:]) default: return nil } // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. } return nil } // Copy returns a deep copy of a conf map. // // It's important to note that all nested maps should be // map[string]interface{} and not map[interface{}]interface{}. // Use IntfaceKeysToStrings() to convert if necessary. func Copy(mp map[string]interface{}) map[string]interface{} { out, _ := copystructure.Copy(&mp) if res, ok := out.(*map[string]interface{}); ok { return *res } return map[string]interface{}{} } // IntfaceKeysToStrings recursively converts map[interface{}]interface{} to // map[string]interface{}. Some parses such as YAML unmarshal return this. func IntfaceKeysToStrings(mp map[string]interface{}) { for key, val := range mp { switch cur := val.(type) { case map[interface{}]interface{}: x := make(map[string]interface{}) for k, v := range cur { x[fmt.Sprintf("%v", k)] = v } mp[key] = x IntfaceKeysToStrings(x) case []interface{}: for i, v := range cur { switch sub := v.(type) { case map[interface{}]interface{}: x := make(map[string]interface{}) for k, v := range sub { x[fmt.Sprintf("%v", k)] = v } cur[i] = x IntfaceKeysToStrings(x) case map[string]interface{}: IntfaceKeysToStrings(sub) } } case map[string]interface{}: IntfaceKeysToStrings(cur) } } } // StringSliceToLookupMap takes a slice of strings and returns a lookup map // with the slice values as keys with true values. func StringSliceToLookupMap(s []string) map[string]bool { mp := make(map[string]bool, len(s)) for _, v := range s { mp[v] = true } return mp } // Int64SliceToLookupMap takes a slice of int64s and returns a lookup map // with the slice values as keys with true values. func Int64SliceToLookupMap(s []int64) map[int64]bool { mp := make(map[int64]bool, len(s)) for _, v := range s { mp[v] = true } return mp } koanf-providers-vault-v2.0.1/mock/000077500000000000000000000000001454017643500171045ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/mock/mock.env000066400000000000000000000002031454017643500205420ustar00rootroot00000000000000lower=case UPPER=CASE MiXeD=CaSe COMMENT=AFTER # Comment # COMMENT MORE=vars quotedSpecial="j18120734xn2&*@#*&R#d1j23d*(*)" empty= koanf-providers-vault-v2.0.1/mock/mock.hcl000066400000000000000000000017251454017643500205320ustar00rootroot00000000000000"bools" = [true, false, true] "empty" = {} "intbools" = [1, 0, 1] "orphan" = ["red", "blue", "orange"] "parent1" = { "boolmap" = { "notok3" = false "ok1" = true "ok2" = true } "child1" = { "empty" = {} "grandchild1" = { "ids" = [1, 2, 3] "on" = true } "name" = "child1" "type" = "hcl" } "floatmap" = { "key1" = 1.1 "key2" = 1.2 "key3" = 1.3 } "id" = 1234 "intmap" = { "key1" = 1 "key2" = 1 "key3" = 1 } "name" = "parent1" "strmap" = { "key1" = "val1" "key2" = "val2" "key3" = "val3" } "strsmap" = { "key1" = ["val1", "val2", "val3"] "key2" = ["val4", "val5"] } } "parent2" = { "child2" = { "empty" = {} "grandchild2" = { "ids" = [4, 5, 6] "on" = true } "name" = "child2" } "id" = 5678 "name" = "parent2" } "strbool" = "1" "strbools" = ["1", "t", "f"] "time" = "2019-01-01" "duration" = "3s" "negative_int" = -1234 "type" = "hcl" koanf-providers-vault-v2.0.1/mock/mock.hjson000066400000000000000000000016441454017643500211050ustar00rootroot00000000000000{ # Analog of mock.json in hjson type: hjson parent1: { name: parent1 id: 1234 child1: { name: child1 type: hjson grandchild1: { ids: [ 1, 2, 3, ] on: true } empty: {} } strmap: { key1: val1 key2: val2 key3: val3 } strsmap: { key1: [ val1 val2 val3 ] key2: [ val4 val5 ] } intmap: { key1: 1 key2: 1 key3: 1 } floatmap: { key1: 1.1 key2: 1.2 key3: 1.3 } boolmap: { ok1: true ok2: true notok3: false } } parent2: { name: parent2 id: 5678 child2: { name: child2 grandchild2: { ids: [4, 5, 6] on: true } empty: {} } } orphan: [ red blue orange ] empty: {} bools: [ true, false, true, ] intbools: [ 1, 0, 1, ] strbools: [ "1", "t", "f" ] strbool: "1" time: "2019-01-01" duration: "3s" negative_int: -1234 } koanf-providers-vault-v2.0.1/mock/mock.json000066400000000000000000000025131454017643500207310ustar00rootroot00000000000000{ "type": "json", "parent1": { "name": "parent1", "id": 1234, "child1": { "name": "child1", "type": "json", "grandchild1": { "ids": [1,2,3], "on": true }, "empty": {} }, "strmap": { "key1": "val1", "key2": "val2", "key3": "val3" }, "strsmap": { "key1": ["val1", "val2", "val3"], "key2": ["val4", "val5"] }, "intmap": { "key1": 1, "key2": 1, "key3": 1 }, "floatmap": { "key1": 1.1, "key2": 1.2, "key3": 1.3 }, "boolmap": { "ok1": true, "ok2": true, "notok3": false } }, "parent2": { "name": "parent2", "id": 5678, "child2": { "name": "child2", "grandchild2": { "ids": [4,5,6], "on": true }, "empty": {} } }, "orphan": ["red", "blue", "orange"], "empty": {}, "bools": [true, false, true], "intbools": [1, 0, 1], "strbools": ["1", "t", "f"], "strbool": "1", "time": "2019-01-01", "duration": "3s", "negative_int": -1234 } koanf-providers-vault-v2.0.1/mock/mock.prop000066400000000000000000000007461454017643500207460ustar00rootroot00000000000000type=prop parent1.name=parent1 parent1.id=1234 parent1.child1.name=child1 parent1.child1.type=prop parent1.child1.grandchild1.ids.0=1 parent1.child1.grandchild1.ids.1=2 parent1.child1.grandchild1.ids.2=3 parent1.child1.grandchild1.on=true parent2.name=parent2 parent2.id=5678 parent2.child2.name=child2 parent2.child2.grandchild2.ids.0=4 parent2.child2.grandchild2.ids.1=5 parent2.child2.grandchild2.ids.2=6 parent2.child2.grandchild2.on=true orphan.0=red orphan.1=blue orphan.2=orange koanf-providers-vault-v2.0.1/mock/mock.toml000066400000000000000000000020041454017643500207260ustar00rootroot00000000000000type = "toml" orphan = [ "red", "blue", "orange" ] bools = [ true, false, true ] intbools = [ 1.0, 0.0, 1.0 ] strbools = [ "1", "t", "f" ] strbool = "1" time = "2019-01-01" duration = "3s" negative_int = -1234 [parent1] name = "parent1" id = 1234.0 [parent1.child1] name = "child1" type = "toml" [parent1.child1.grandchild1] ids = [ 1.0, 2.0, 3.0 ] on = true [parent1.child1.empty] [parent1.strmap] key1 = "val1" key2 = "val2" key3 = "val3" [parent1.strsmap] key1 = [ "val1", "val2", "val3" ] key2 = [ "val4", "val5" ] [parent1.intmap] key1 = 1.0 key2 = 1.0 key3 = 1.0 [parent1.floatmap] key1 = 1.1 key2 = 1.2 key3 = 1.3 [parent1.boolmap] ok1 = true ok2 = true notok3 = false [parent2] name = "parent2" id = 5678.0 [parent2.child2] name = "child2" [parent2.child2.grandchild2] ids = [ 4.0, 5.0, 6.0 ] on = true [parent2.child2.empty] [empty] koanf-providers-vault-v2.0.1/mock/mock.yml000066400000000000000000000015321454017643500205610ustar00rootroot00000000000000--- type: yml parent1: name: parent1 id: 1234 child1: name: child1 type: yml grandchild1: ids: - 1 - 2 - 3 "on": true empty: {} strmap: key1: val1 key2: val2 key3: val3 strsmap: key1: - val1 - val2 - val3 key2: - val4 - val5 intmap: key1: 1 key2: 1 key3: 1 floatmap: key1: 1.1 key2: 1.2 key3: 1.3 boolmap: ok1: true ok2: true notok3: false parent2: name: parent2 id: 5678 child2: name: child2 grandchild2: ids: - 4 - 5 - 6 "on": true empty: {} orphan: - red - blue - orange empty: {} bools: - true - false - true intbools: - 1 - 0 - 1 strbools: - "1" - t - f strbool: "1" time: "2019-01-01" duration: "3s" negative_int: -1234 koanf-providers-vault-v2.0.1/options.go000066400000000000000000000015011454017643500201720ustar00rootroot00000000000000package koanf // options contains options to modify the behavior of Koanf.Load. type options struct { merge func(a, b map[string]interface{}) error } // newOptions creates a new options instance. func newOptions(opts []Option) *options { o := new(options) o.apply(opts) return o } // Option is a generic type used to modify the behavior of Koanf.Load. type Option func(*options) // apply the given options. func (o *options) apply(opts []Option) { for _, opt := range opts { opt(o) } } // WithMergeFunc is an option to modify the merge behavior of Koanf.Load. // If unset, the default merge function is used. // // The merge function is expected to merge map src into dest (left to right). func WithMergeFunc(merge func(src, dest map[string]interface{}) error) Option { return func(o *options) { o.merge = merge } } koanf-providers-vault-v2.0.1/parsers/000077500000000000000000000000001454017643500176325ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/dotenv/000077500000000000000000000000001454017643500211315ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/dotenv/dotenv.go000066400000000000000000000037651454017643500227720ustar00rootroot00000000000000// Package dotenv implements a koanf.Parser that parses DOTENV bytes as conf maps. package dotenv import ( "fmt" "strings" "github.com/joho/godotenv" "github.com/knadh/koanf/maps" ) // DotEnv implements a DOTENV parser. type DotEnv struct { delim string prefix string cb func(key string, value string) (string, interface{}) reverseCB map[string]string } // Parser returns a DOTENV Parser. func Parser() *DotEnv { return &DotEnv{} } // ParserEnv allows to make the DOTENV Parser behave like the env.Provider. func ParserEnv(prefix, delim string, cb func(s string) string) *DotEnv { return &DotEnv{ delim: delim, prefix: prefix, cb: func(key, value string) (string, interface{}) { return cb(key), value }, reverseCB: make(map[string]string), } } // Unmarshal parses the given DOTENV bytes. func (p *DotEnv) Unmarshal(b []byte) (map[string]interface{}, error) { // Unmarshal DOTENV from []byte r, err := godotenv.Unmarshal(string(b)) if err != nil { return nil, err } // Convert a map[string]string to a map[string]interface{} mp := make(map[string]interface{}) for sourceKey, v := range r { if !strings.HasPrefix(sourceKey, p.prefix) { continue } if p.cb != nil { targetKey, value := p.cb(sourceKey, v) p.reverseCB[targetKey] = sourceKey mp[targetKey] = value } else { mp[sourceKey] = v } } if p.delim != "" { mp = maps.Unflatten(mp, p.delim) } return mp, nil } // Marshal marshals the given config map to DOTENV bytes. func (p *DotEnv) Marshal(o map[string]interface{}) ([]byte, error) { if p.delim != "" { o, _ = maps.Flatten(o, nil, p.delim) } // Convert a map[string]interface{} to a map[string]string mp := make(map[string]string) for targetKey, v := range o { if sourceKey, found := p.reverseCB[targetKey]; found { targetKey = sourceKey } mp[targetKey] = fmt.Sprint(v) } // Unmarshal to string out, err := godotenv.Marshal(mp) if err != nil { return nil, err } // Convert to []byte and return return []byte(out), nil } koanf-providers-vault-v2.0.1/parsers/dotenv/dotenv_test.go000066400000000000000000000111221454017643500240130ustar00rootroot00000000000000package dotenv import ( "strings" "testing" "github.com/stretchr/testify/assert" ) func TestDotEnv_Marshal(t *testing.T) { de := DotEnv{} testCases := []struct { name string cfg map[string]interface{} expOut []byte err error }{ { name: "Empty config", cfg: map[string]interface{}{}, expOut: []byte{}, }, { name: "Simple key-value pair", cfg: map[string]interface{}{ "key": "value", }, expOut: []byte("key=\"value\""), }, { name: "Multiple key-values", cfg: map[string]interface{}{ "key-1": "value-1", "key-2": "value-2", "key-3": "value-3", }, expOut: []byte("key-1=\"value-1\"\nkey-2=\"value-2\"\nkey-3=\"value-3\""), }, { name: "Mixed data types", cfg: map[string]interface{}{ "int-key": 12, "bool-key": true, "arr-key": []int{1, 2, 3, 4}, "float-key": 10.5, }, expOut: []byte("arr-key=\"[1 2 3 4]\"\nbool-key=\"true\"\nfloat-key=\"10.5\"\nint-key=\"12\""), }, { name: "Nested config", cfg: map[string]interface{}{ "map-key": map[string]interface{}{ "arr-key": []float64{1.2, 4.3, 5, 6}, "bool-key": false, "inner-map-key": map[interface{}]interface{}{ 0: "zero", 1: 1.0, }, "int-key": 12, }, }, expOut: []byte(`map-key="map[arr-key:[1.2 4.3 5 6] bool-key:false inner-map-key:map[0:zero 1:1] int-key:12]"`), }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := de.Marshal(tc.cfg) assert.Equal(t, tc.err, err) assert.Equal(t, string(tc.expOut), string(out)) }) } } func TestDotEnv_Unmarshal(t *testing.T) { de := DotEnv{} testCases := []struct { name string cfg []byte expOut map[string]interface{} err error }{ { name: "Empty config", expOut: map[string]interface{}{}, }, { name: "Simple key-value", cfg: []byte(`key="value"`), expOut: map[string]interface{}{ "key": "value", }, }, { name: "Multiple key-values", cfg: []byte("key-1=\"value-1\"\nkey-2=\"value-2\""), expOut: map[string]interface{}{ "key-1": "value-1", "key-2": "value-2", }, }, { name: "Mixed data types", cfg: []byte("arr=\"[1 2 3 4]\"\nbool=\"true\"\nfloat=\"12.5\"\nint=\"32\"\n"), expOut: map[string]interface{}{ "arr": "[1 2 3 4]", "bool": "true", "float": "12.5", "int": "32", }, }, { name: "Nested config", cfg: []byte(`map-key="map[arr-key:[1 4 5 6] bool-key:false inner-map-key:map[0:zero 1:1] int-key:12]"`), expOut: map[string]interface{}{ "map-key": "map[arr-key:[1 4 5 6] bool-key:false inner-map-key:map[0:zero 1:1] int-key:12]", }, }, { name: "Missing quotation mark", cfg: []byte(`key="value`), expOut: map[string]interface{}{ "key": `"value`, }, }, { name: "Missing value", cfg: []byte(`key=`), expOut: map[string]interface{}{ "key": "", }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { outMap, err := de.Unmarshal(tc.cfg) assert.Equal(t, tc.err, err) assert.Equal(t, tc.expOut, outMap) }) } } func TestCompareToEnvProvider(t *testing.T) { testCases := []struct { name string prefix string delim string key string value string expKey string expValue string cb func(key string) string want *DotEnv }{ { name: "Nil cb", prefix: "TESTVAR_", delim: ".", want: &DotEnv{ prefix: "TESTVAR_", delim: ".", }, }, { name: "Simple cb", prefix: "TESTVAR_", delim: ".", key: "TestKey", value: "TestVal", expKey: "testkey", expValue: "TestVal", cb: func(key string) string { return strings.ToLower(key) }, want: &DotEnv{ prefix: "TESTVAR_", delim: ".", }, }, { name: "Empty string nil cb", prefix: "", delim: ".", want: &DotEnv{ prefix: "", delim: ".", }, }, { name: "Cb is given", prefix: "", delim: ".", key: "test_key", value: "test_val", expKey: "TEST.KEY", expValue: "test_val", cb: func(key string) string { return strings.Replace(strings.ToUpper(key), "_", ".", -1) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { gotProvider := ParserEnv(tc.prefix, tc.delim, tc.cb) if tc.cb == nil { assert.Equal(t, tc.prefix, gotProvider.prefix) assert.Equal(t, tc.delim, gotProvider.delim) // do not compare cb or reverseCB } if tc.cb != nil { k, v := gotProvider.cb(tc.key, tc.value) assert.Equal(t, tc.expKey, k) assert.Equal(t, tc.expValue, v) } }) } } koanf-providers-vault-v2.0.1/parsers/dotenv/go.mod000066400000000000000000000006531454017643500222430ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/dotenv go 1.18 require ( github.com/joho/godotenv v1.5.1 github.com/knadh/koanf/maps v0.1.1 github.com/stretchr/testify v1.8.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/parsers/dotenv/go.sum000066400000000000000000000042641454017643500222720ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/parsers/hcl/000077500000000000000000000000001454017643500204005ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/hcl/go.mod000066400000000000000000000004301454017643500215030ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/hcl go 1.18 require ( github.com/hashicorp/hcl v1.0.0 github.com/stretchr/testify v1.8.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/parsers/hcl/go.sum000066400000000000000000000032251454017643500215350ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/parsers/hcl/hcl.go000066400000000000000000000040511454017643500214750ustar00rootroot00000000000000// Package hcl implements a koanf.Parser that parses Hashicorp // HCL bytes as conf maps. package hcl import ( "errors" "github.com/hashicorp/hcl" ) // HCL implements a Hashicorp HCL parser. type HCL struct{ flattenSlices bool } // Parser returns an HCL Parser. // flattenSlices flattens HCL structures where maps turn into // lists of maps. Read more here: https://github.com/hashicorp/hcl/issues/162 // It's recommended to turn this setting on. func Parser(flattenSlices bool) *HCL { return &HCL{flattenSlices: flattenSlices} } // Unmarshal parses the given HCL bytes. func (p *HCL) Unmarshal(b []byte) (map[string]interface{}, error) { o, err := hcl.Parse(string(b)) if err != nil { return nil, err } var out map[string]interface{} if err := hcl.DecodeObject(&out, o); err != nil { return nil, err } if p.flattenSlices { flattenHCL(out) } return out, nil } // Marshal marshals the given config map to HCL bytes. func (p *HCL) Marshal(o map[string]interface{}) ([]byte, error) { return nil, errors.New("HCL marshalling is not supported") // TODO: Although this is the only way to do it, it's producing empty bytes. // Needs investigation. // The only way to generate HCL is from the HCL node structure. // Turn the map into JSON, then parse it with the HCL lib to create its // structure, and then, encode to HCL. // j, err := json.Marshal(o) // if err != nil { // return nil, err // } // tree, err := hcl.Parse(string(j)) // if err != nil { // return nil, err // } // var buf bytes.Buffer // out := bufio.NewWriter(&buf) // if err := printer.Fprint(out, tree.Node); err != nil { // return nil, err // } // return buf.Bytes(), err } // flattenHCL flattens an unmarshalled HCL structure where maps // turn into slices -- https://github.com/hashicorp/hcl/issues/162. func flattenHCL(mp map[string]interface{}) { for k, val := range mp { if v, ok := val.([]map[string]interface{}); ok { if len(v) == 1 { mp[k] = v[0] } } } for _, val := range mp { if v, ok := val.(map[string]interface{}); ok { flattenHCL(v) } } } koanf-providers-vault-v2.0.1/parsers/hcl/hcl_test.go000066400000000000000000000067141454017643500225440ustar00rootroot00000000000000package hcl import ( "testing" "github.com/stretchr/testify/assert" ) func TestHCL_Unmarshal(t *testing.T) { hclParserWithFlatten := Parser(true) hclParserWithoutFlatten := Parser(false) testCases := []struct { name string input []byte output map[string]interface{} isErr bool function HCL }{ { name: "Empty HCL - With faltten", input: []byte(`{}`), function: *hclParserWithFlatten, output: map[string]interface{}{}, }, { name: "Empty HCL - Without flatten", input: []byte(`{}`), function: *hclParserWithoutFlatten, output: map[string]interface{}{}, }, { name: "Valid HCL - With faltten", input: []byte(`resource "aws_instance" "example" { count = 2 # meta-argument first ami = "abc123" instance_type = "t2.micro" lifecycle { # meta-argument block last create_before_destroy = true } }`), function: *hclParserWithFlatten, output: map[string]interface{}{ "resource": map[string]interface{}{ "aws_instance": map[string]interface{}{ "example": map[string]interface{}{ "ami": "abc123", "count": 2, "instance_type": "t2.micro", "lifecycle": map[string]interface{}{ "create_before_destroy": true, }, }, }, }, }, }, { name: "Valid HCL - Without faltten", input: []byte(`resource "aws_instance" "example" { count = 2 # meta-argument first ami = "abc123" instance_type = "t2.micro" lifecycle { # meta-argument block last create_before_destroy = true } }`), function: *hclParserWithoutFlatten, output: map[string]interface{}{ "resource": []map[string]interface{}{{ "aws_instance": []map[string]interface{}{{ "example": []map[string]interface{}{{ "ami": "abc123", "count": 2, "instance_type": "t2.micro", "lifecycle": []map[string]interface{}{{ "create_before_destroy": true}, }, }}, }}, }}, }, }, { name: "Invalid HCL - With missing parenthesis", input: []byte(`resource "aws_instance" "example" { ami = "abc123" `), function: *hclParserWithFlatten, isErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := tc.function.Unmarshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) assert.Equal(t, tc.output, out) } }) } } func TestHCL_Marshal(t *testing.T) { hclParserWithFlatten := Parser(true) testCases := []struct { name string input map[string]interface{} isErr bool function HCL }{ { name: "Empty HCL", input: map[string]interface{}{}, isErr: true, function: *hclParserWithFlatten, }, { name: "Complex HCL", input: map[string]interface{}{ "resource": []map[string]interface{}{{ "aws_instance": []map[string]interface{}{{ "example": []map[string]interface{}{{ "ami": "abc123", "count": 2, "instance_type": "t2.micro", "lifecycle": []map[string]interface{}{{ "create_before_destroy": true}, }, }}, }}, }}, }, isErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { _, err := tc.function.Marshal(tc.input) if tc.isErr { assert.EqualError(t, err, "HCL marshalling is not supported") } else { assert.Nil(t, err) } }) } } koanf-providers-vault-v2.0.1/parsers/hjson/000077500000000000000000000000001454017643500207535ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/hjson/go.mod000066400000000000000000000004361454017643500220640ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/hjson go 1.18 require ( github.com/hjson/hjson-go/v4 v4.3.0 github.com/stretchr/testify v1.8.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/parsers/hjson/go.sum000066400000000000000000000032351454017643500221110ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/hjson/hjson-go/v4 v4.3.0 h1:dyrzJdqqFGhHt+FSrs5n9s6b0fPM8oSJdWo+oS3YnJw= github.com/hjson/hjson-go/v4 v4.3.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/parsers/hjson/hjson.go000066400000000000000000000012571454017643500224300ustar00rootroot00000000000000// Package hjson implements a koanf.Parser that parses HJSON bytes as conf maps. // Very similar to json. package hjson import ( "github.com/hjson/hjson-go/v4" ) // HJSON implements a HJSON parser. type HJSON struct{} // Parser returns a HJSON parser. func Parser() *HJSON { return &HJSON{} } // Unmarshal parses the given HJSON bytes. func (p *HJSON) Unmarshal(b []byte) (map[string]interface{}, error) { var out map[string]interface{} if err := hjson.Unmarshal(b, &out); err != nil { return nil, err } return out, nil } // Marshal marshals the given config map to HJSON bytes. func (p *HJSON) Marshal(o map[string]interface{}) ([]byte, error) { return hjson.Marshal(o) } koanf-providers-vault-v2.0.1/parsers/hjson/hjson_test.go000066400000000000000000000131261454017643500234650ustar00rootroot00000000000000package hjson import ( "github.com/stretchr/testify/assert" "testing" ) func TestHJSON_Unmarshal(t *testing.T) { testCases := []struct { name string input []byte keys []string values []interface{} isErr bool }{ { name: "Empty HJSON", input: []byte(`{}`), }, { name: "Valid HJSON", input: []byte(`{ key: val name: test number: 2 }`), keys: []string{"key", "name", "number"}, values: []interface{}{"val", "test", 2.0}, }, { name: "Commented HJSON", input: []byte(`{ # hash style comments # (because it's just one character) // line style comments // (because it's like C/JavaScript/...) /* block style comments because it allows you to comment out a block */ key: v1 name: Comments number: 3 }`), keys: []string{"key", "name", "number"}, values: []interface{}{"v1", "Comments", 3.0}, }, { name: "Quoted strings HJSON", input: []byte(`{ JSON: "a string" HJSON: a string #notice, no escape necessary: RegEx: \s+ }`), keys: []string{"JSON", "HJSON", "RegEx"}, values: []interface{}{"a string", "a string", `\s+`}, }, { name: "Multiline strings HJSON", input: []byte(`{ md: ''' First line. Second line. This line is indented by two spaces. ''' }`), keys: []string{"md"}, values: []interface{}{"First line.\nSecond line.\n This line is indented by two spaces."}, }, { name: "Punctuators HJSON", input: []byte(`{ "key name": "{ sample }" "()": " sample at the start/end " this: is OK though: {}[],: }`), keys: []string{"key name", "()", "this"}, values: []interface{}{"{ sample }", " sample at the start/end ", "is OK though: {}[],:"}, }, { name: "Invalid HJSON - missing curly brace", input: []byte(`{ key: val,`), isErr: true, }, { name: "Comma HJSON", input: []byte(`{ key: a, key_n: 3 key3: b, }`), keys: []string{"key", "key_n", "key3"}, values: []interface{}{"a,", 3.0, "b,"}, }, { name: "One quote in key - HJSON", input: []byte(`{ "key: a "key2": b }`), isErr: true, }, { name: "Comment without marks HJSON", input: []byte(`{ Wrong commentary without #, // or /**/ key: 1 }`), isErr: true, }, { name: "Wrong comment mark HJSON", input: []byte(`{ $ Wrong comment mark key: a }`), isErr: true, }, { name: "Wrong line style comment HJSON", input: []byte(`{ / Wrong comment - / instead of // key: a }`), isErr: true, }, { name: "Wrong multiline style comment HJSON", input: []byte(`{ /* Multiline comment without second mark key: b }`), isErr: true, }, { name: "Whitespace in the key - HJSON", input: []byte(`{ key whitespace: a }`), isErr: true, }, { name: "Punctuator (comma) in the key - HJSON", input: []byte(`{ key, comma: a }`), isErr: true, }, { name: "Complex HJSON - all types", input: []byte(`{ # All types // and comments /* including multiline style comments */ array: [ 1, 2, 3 ] boolean: true, color: gold null: null number: 123 object: { "a": "b", "c": "d" }, string: "Hello World" }`), keys: []string{"array", "boolean", "color", "null", "number", "object", "string"}, values: []interface{}{[]interface{}{1.0, 2.0, 3.0}, true, "gold", nil, 123.0, map[string]interface{}{"a": "b", "c": "d"}, "Hello World"}, }, } h := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := h.Unmarshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) for i, k := range tc.keys { v := out[k] assert.Equal(t, tc.values[i], v) } } }) } } func TestHJSON_Marshal(t *testing.T) { testCases := []struct { name string input map[string]interface{} output map[string]interface{} }{ { name: "Empty HJSON", input: map[string]interface{}{}, output: map[string]interface{}{}, }, { name: "Valid HJSON", input: map[string]interface{}{ "key": "val", "name": "test", "number": 2.0, }, output: map[string]interface{}{ "key": "val", "name": "test", "number": 2.0, }, }, { name: "Multiline value HJSON", input: map[string]interface{}{ "md": ` ''' First line. Second line. This line is indented by two spaces. '''`, }, output: map[string]interface{}{ "md": ` ''' First line. Second line. This line is indented by two spaces. '''`, }, }, { name: "Complex HJSON - All types", input: map[string]interface{}{ "array": []interface{}{1, 2, 3, 4, 5}, "boolean": true, "color": "red", "null": nil, "number": 123, "object": map[string]interface{}{"a": "b", "c": "d"}, "string": "Hello HJSON", }, output: map[string]interface{}{ "array": []interface{}{1.0, 2.0, 3.0, 4.0, 5.0}, "boolean": true, "color": "red", "null": nil, "number": 123.0, "object": map[string]interface{}{"a": "b", "c": "d"}, "string": "Hello HJSON", }, }, } h := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { buf, err := h.Marshal(tc.input) assert.Nil(t, err) out, err := h.Unmarshal(buf) assert.Nil(t, err) for key, val := range out { assert.Equal(t, tc.output[key], val) } }) } } koanf-providers-vault-v2.0.1/parsers/json/000077500000000000000000000000001454017643500206035ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/json/go.mod000066400000000000000000000003631454017643500217130ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/json go 1.18 require github.com/stretchr/testify v1.8.1 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/parsers/json/go.sum000066400000000000000000000027561454017643500217500ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/parsers/json/json.go000066400000000000000000000011701454017643500221020ustar00rootroot00000000000000// Package json implements a koanf.Parser that parses JSON bytes as conf maps. package json import ( "encoding/json" ) // JSON implements a JSON parser. type JSON struct{} // Parser returns a JSON Parser. func Parser() *JSON { return &JSON{} } // Unmarshal parses the given JSON bytes. func (p *JSON) Unmarshal(b []byte) (map[string]interface{}, error) { var out map[string]interface{} if err := json.Unmarshal(b, &out); err != nil { return nil, err } return out, nil } // Marshal marshals the given config map to JSON bytes. func (p *JSON) Marshal(o map[string]interface{}) ([]byte, error) { return json.Marshal(o) } koanf-providers-vault-v2.0.1/parsers/json/json_test.go000066400000000000000000000055441454017643500231520ustar00rootroot00000000000000package json import ( "github.com/stretchr/testify/assert" "testing" ) func TestJSON_Unmarshal(t *testing.T) { testCases := []struct { name string input []byte keys []string values []interface{} isErr bool }{ { name: "Empty JSON", input: []byte(`{}`), }, { name: "Valid JSON", input: []byte(`{ "key": "val", "name": "test", "number": 2 }`), keys: []string{"key", "name", "number"}, values: []interface{}{"val", "test", 2.0}, }, { name: "Invalid JSON - missing curly brace", input: []byte(`{ "key": "val",`), isErr: true, }, { name: "Complex JSON - All types", input: []byte(`{ "array": [ 1, 2, 3 ], "boolean": true, "color": "gold", "null": null, "number": 123, "object": { "a": "b", "c": "d" }, "string": "Hello World" }`), keys: []string{"array", "boolean", "color", "null", "number", "object", "string"}, values: []interface{}{[]interface{}{1.0, 2.0, 3.0}, true, "gold", nil, 123.0, map[string]interface{}{"a": "b", "c": "d"}, "Hello World"}, }, { name: "Invalid JSON - missing comma", input: []byte(`{ "boolean": true "number": 123 }`), isErr: true, }, { name: "Invalid JSON - Redundant comma", input: []byte(`{ "number": 123, }`), isErr: true, }, } j := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := j.Unmarshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) for i, k := range tc.keys { v := out[k] assert.Equal(t, tc.values[i], v) } } }) } } func TestJSON_Marshal(t *testing.T) { testCases := []struct { name string input map[string]interface{} output []byte isErr bool }{ { name: "Empty JSON", input: map[string]interface{}{}, output: []byte(`{}`), }, { name: "Valid JSON", input: map[string]interface{}{ "key": "val", "name": "test", "number": 2.0, }, output: []byte(`{"key":"val","name":"test","number":2}`), }, { name: "Complex JSON - All types", input: map[string]interface{}{ "array": []interface{}{1, 2, 3, 4, 5}, "boolean": true, "color": "gold", "null": nil, "number": 123, "object": map[string]interface{}{"a": "b", "c": "d"}, "string": "Hello World", }, output: []byte(`{"array":[1,2,3,4,5],"boolean":true,"color":"gold","null":null,"number":123,"object":{"a":"b","c":"d"},"string":"Hello World"}`), }, } j := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := j.Marshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) assert.Equal(t, tc.output, out) } }) } } koanf-providers-vault-v2.0.1/parsers/nestedtext/000077500000000000000000000000001454017643500220215ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/nestedtext/go.mod000066400000000000000000000001501454017643500231230ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/nestedtext go 1.18 require github.com/npillmayer/nestext v0.1.3 koanf-providers-vault-v2.0.1/parsers/nestedtext/go.sum000066400000000000000000000002611454017643500231530ustar00rootroot00000000000000github.com/npillmayer/nestext v0.1.3 h1:2dkbzJ5xMcyJW5b8wwrX+nnRNvf/Nn1KwGhIauGyE2E= github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= koanf-providers-vault-v2.0.1/parsers/nestedtext/nestedtext.go000066400000000000000000000026071454017643500245440ustar00rootroot00000000000000// Package nestedtext implements a koanf Parser that parses NestedText bytes as conf maps. package nestedtext import ( "bytes" "errors" "github.com/npillmayer/nestext" "github.com/npillmayer/nestext/ntenc" ) // NT implements a NestedText parser. type NT struct{} // Parser returns a NestedText Parser. func Parser() *NT { return &NT{} } // Unmarshal parses the given NestedText bytes. // // If the NT content does not reflect a dict (NT allows for top-level lists or strings as well), // the content will be wrapped into a dict with a single key named "nestedtext". func (p *NT) Unmarshal(b []byte) (map[string]interface{}, error) { r := bytes.NewReader(b) result, err := nestext.Parse(r, nestext.TopLevel("dict")) if err != nil { return nil, err } // Given option-parameter TopLevel, nestext.Parse is guaranteed to wrap the return value // in an appropriate type (dict = map[string]interface{} in this case), if necessary. // However, guard against type conversion failure anyway. rmap, ok := result.(map[string]interface{}) if !ok { return nil, errors.New("NestedText configuration expected to be a dict at top-level") } return rmap, nil } // Marshal marshals the given config map to NestedText bytes. func (p *NT) Marshal(m map[string]interface{}) ([]byte, error) { var buf bytes.Buffer _, err := ntenc.Encode(m, &buf) if err != nil { return nil, err } return buf.Bytes(), nil } koanf-providers-vault-v2.0.1/parsers/nestedtext/nt_test.go000066400000000000000000000014501454017643500240300ustar00rootroot00000000000000package nestedtext_test import ( "testing" "github.com/knadh/koanf/parsers/nestedtext" ) func TestParser(t *testing.T) { // test input in NestedText format ntsource := `ports: - 6483 - 8020 - 9332 timeout: 20 ` // Test decoder nt := nestedtext.Parser() c, err := nt.Unmarshal([]byte(ntsource)) if err != nil { t.Fatal("Unmarshal of NestedText input failed") } timeout := c["timeout"] if timeout != "20" { t.Logf("config-tree: %#v", c) t.Errorf("expected timeout-parameter to be 20, is %q", timeout) } // test encoder out, err := nt.Marshal(c) if err != nil { t.Fatal("Marshal of config to NestedText failed") } if string(out) != ntsource { t.Logf("config-text: %q", string(out)) t.Errorf("expected output of Marshal(…) to equal input to Unmarshal(…); didn't") } } koanf-providers-vault-v2.0.1/parsers/toml/000077500000000000000000000000001454017643500206055ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/toml/go.mod000066400000000000000000000004351454017643500217150ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/toml go 1.18 require ( github.com/pelletier/go-toml v1.9.5 github.com/stretchr/testify v1.8.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/parsers/toml/go.sum000066400000000000000000000032351454017643500217430ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/parsers/toml/toml.go000066400000000000000000000013131454017643500221050ustar00rootroot00000000000000// Package toml implements a koanf.Parser that parses TOML bytes as conf maps. package toml import ( "bytes" "github.com/pelletier/go-toml" ) // TOML implements a TOML parser. type TOML struct{} // Parser returns a TOML Parser. func Parser() *TOML { return &TOML{} } // Unmarshal parses the given TOML bytes. func (p *TOML) Unmarshal(b []byte) (map[string]interface{}, error) { r, err := toml.LoadReader(bytes.NewBuffer(b)) if err != nil { return nil, err } return r.ToMap(), err } // Marshal marshals the given config map to TOML bytes. func (p *TOML) Marshal(o map[string]interface{}) ([]byte, error) { out, err := toml.TreeFromMap(o) if err != nil { return nil, err } return out.Marshal() } koanf-providers-vault-v2.0.1/parsers/toml/toml_test.go000066400000000000000000000050171454017643500231510ustar00rootroot00000000000000package toml import ( "testing" "github.com/stretchr/testify/assert" ) func TestTOML_Unmarshal(t *testing.T) { testCases := []struct { name string input []byte output map[string]interface{} isErr bool }{ { name: "Empty TOML", input: []byte(``), output: map[string]interface{}{}, }, { name: "Valid TOML", input: []byte(`key = "val" name = "test" number = 2 `), output: map[string]interface{}{ "key": "val", "name": "test", "number": int64(2), }, }, { name: "Invalid TOML - missing end quotes", input: []byte(`key = "val`), isErr: true, }, { name: "Complex TOML - All types", input: []byte(`array = [ 1, 2, 3 ] boolean = true color = "gold" number = 123 string = "Hello World" [object] a = "b" c = "d"`), output: map[string]interface{}{ "array": []interface{}{int64(1), int64(2), int64(3)}, "boolean": true, "color": "gold", "number": int64(123), "object": map[string]interface{}{"a": "b", "c": "d"}, "string": "Hello World", }, }, { name: "Invalid TOML - missing equal", input: []byte(`key "val"`), isErr: true, }, } tp := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := tp.Unmarshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) assert.Equal(t, tc.output, out) } }) } } func TestTOML_Marshal(t *testing.T) { testCases := []struct { name string input map[string]interface{} output []byte isErr bool }{ { name: "Empty TOML", input: map[string]interface{}{}, output: []byte(nil), }, { name: "Valid TOML", input: map[string]interface{}{ "key": "val", "name": "test", "number": 2.0, }, output: []byte(`key = "val" name = "test" number = 2.0 `), }, { name: "Complex TOML - All types", input: map[string]interface{}{ "array": []interface{}{1, 2, 3, 4, 5}, "boolean": true, "color": "gold", "number": 123, "object": map[string]interface{}{"a": "b", "c": "d"}, "string": "Hello World", }, output: []byte(`array = [1,2,3,4,5] boolean = true color = "gold" number = 123 string = "Hello World" [object] a = "b" c = "d" `), }, } tp := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := tp.Marshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) assert.Equal(t, tc.output, out) } }) } } koanf-providers-vault-v2.0.1/parsers/yaml/000077500000000000000000000000001454017643500205745ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/parsers/yaml/go.mod000066400000000000000000000003541454017643500217040ustar00rootroot00000000000000module github.com/knadh/koanf/parsers/yaml go 1.18 require ( github.com/stretchr/testify v1.8.1 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect ) koanf-providers-vault-v2.0.1/parsers/yaml/go.sum000066400000000000000000000027561454017643500217410ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/parsers/yaml/yaml.go000066400000000000000000000011741454017643500220700ustar00rootroot00000000000000// Package yaml implements a koanf.Parser that parses YAML bytes as conf maps. package yaml import ( "gopkg.in/yaml.v3" ) // YAML implements a YAML parser. type YAML struct{} // Parser returns a YAML Parser. func Parser() *YAML { return &YAML{} } // Unmarshal parses the given YAML bytes. func (p *YAML) Unmarshal(b []byte) (map[string]interface{}, error) { var out map[string]interface{} if err := yaml.Unmarshal(b, &out); err != nil { return nil, err } return out, nil } // Marshal marshals the given config map to YAML bytes. func (p *YAML) Marshal(o map[string]interface{}) ([]byte, error) { return yaml.Marshal(o) } koanf-providers-vault-v2.0.1/parsers/yaml/yaml_test.go000066400000000000000000000052741454017643500231340ustar00rootroot00000000000000package yaml import ( "testing" "github.com/stretchr/testify/assert" ) func TestYAML_Unmarshal(t *testing.T) { testCases := []struct { name string input []byte keys []string values []interface{} isErr bool }{ { name: "Empty YAML", input: []byte(`{}`), }, { name: "Valid YAML", input: []byte(`key: val name: test number: 2`), keys: []string{"key", "name", "number"}, values: []interface{}{"val", "test", 2}, }, { name: "Invalid YAML - wrong intendation", input: []byte(`key: val name: test number: 2`), isErr: true, }, { name: "Complex YAML - All types", input: []byte(`--- array: - 1 - 2 - 3 boolean: true color: gold 'null': number: 123 object: a: b c: d string: Hello World`), keys: []string{"array", "boolean", "color", "null", "number", "object", "string"}, values: []interface{}{[]interface{}{1, 2, 3}, true, "gold", nil, 123, map[string]interface{}{"a": "b", "c": "d"}, "Hello World"}, }, { name: "Valid YAML - With comments", input: []byte(`--- key: #Here is a single-line comment - value line 5 #Here is a #multi-line comment - value line 13`), keys: []string{"key"}, values: []interface{}{[]interface{}{"value line 5", "value line 13"}}, }, } y := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := y.Unmarshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) for i, k := range tc.keys { v := out[k] assert.Equal(t, tc.values[i], v) } } }) } } func TestYAML_Marshal(t *testing.T) { testCases := []struct { name string input map[string]interface{} output []byte isErr bool }{ { name: "Empty YAML", input: map[string]interface{}{}, output: []byte(`{} `), }, { name: "Valid YAML", input: map[string]interface{}{ "key": "val", "name": "test", "number": 2, }, output: []byte(`key: val name: test number: 2 `), }, { name: "Complex YAML - All types", input: map[string]interface{}{ "array": []interface{}{1, 2, 3, 4, 5}, "boolean": true, "color": "gold", "null": nil, "number": 123, "object": map[string]interface{}{"a": "b", "c": "d"}, "string": "Hello World", }, output: []byte(`array: - 1 - 2 - 3 - 4 - 5 boolean: true color: gold "null": null number: 123 object: a: b c: d string: Hello World `), }, } y := Parser() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { out, err := y.Marshal(tc.input) if tc.isErr { assert.NotNil(t, err) } else { assert.Nil(t, err) assert.Equal(t, tc.output, out) } }) } } koanf-providers-vault-v2.0.1/providers/000077500000000000000000000000001454017643500201705ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/appconfig/000077500000000000000000000000001454017643500221365ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/appconfig/appconfig.go000066400000000000000000000114151454017643500244350ustar00rootroot00000000000000// Package appconfig implements a koanf.Provider for AWS AppConfig // and provides it to koanf to be parsed by a koanf.Parser. package appconfig import ( "context" "errors" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/credentials/stscreds" "github.com/aws/aws-sdk-go-v2/service/appconfig" "github.com/aws/aws-sdk-go-v2/service/sts" ) // Config holds the AWS AppConfig Configuration. type Config struct { // The AWS AppConfig Application to get. Specify either the application // name or the application ID. Application string // The Client ID for the AppConfig. Enables AppConfig to deploy the // configuration in intervals, as defined in the deployment strategy. ClientID string // The AppConfig configuration to fetch. Specify either the configuration // name or the configuration ID. Configuration string // The AppConfig environment to get. Specify either the environment // name or the environment ID. Environment string // The AppConfig Configuration Version to fetch. Specifying a ClientConfigurationVersion // ensures that the configuration is only fetched if it is updated. If not specified, // the latest available configuration is fetched always. // Setting this to the latest configuration version will return an empty slice of bytes. ClientConfigurationVersion string // The AWS Access Key ID to use. This value is fetched from the environment // if not specified. AWSAccessKeyID string // The AWS Secret Access Key to use. This value is fetched from the environment // if not specified. AWSSecretAccessKey string // The AWS IAM Role ARN to use. Useful for access requiring IAM AssumeRole. AWSRoleARN string // The AWS Region to use. This value is fetched from teh environment if not specified. AWSRegion string // Time interval at which the watcher will refresh the configuration. // Defaults to 60 seconds. WatchInterval time.Duration } // AppConfig implements an AWS AppConfig provider. type AppConfig struct { client *appconfig.Client config Config input appconfig.GetConfigurationInput } // Provider returns an AWS AppConfig provider. func Provider(cfg Config) (*AppConfig, error) { c, err := config.LoadDefaultConfig(context.TODO()) if err != nil { return nil, err } if cfg.AWSRegion != "" { c.Region = cfg.AWSRegion } // Check if AWS Access Key ID and Secret Key are specified. if cfg.AWSAccessKeyID != "" && cfg.AWSSecretAccessKey != "" { c.Credentials = credentials.NewStaticCredentialsProvider(cfg.AWSAccessKeyID, cfg.AWSSecretAccessKey, "") } // Check if AWS Role ARN is present. if cfg.AWSRoleARN != "" { stsSvc := sts.NewFromConfig(c) credentials := stscreds.NewAssumeRoleProvider(stsSvc, cfg.AWSRoleARN) c.Credentials = aws.NewCredentialsCache(credentials) } client := appconfig.NewFromConfig(c) return &AppConfig{client: client, config: cfg}, nil } // ProviderWithClient returns an AWS AppConfig provider // using an existing AWS appconfig client. func ProviderWithClient(cfg Config, client *appconfig.Client) *AppConfig { return &AppConfig{client: client, config: cfg} } // ReadBytes returns the raw bytes for parsing. func (ac *AppConfig) ReadBytes() ([]byte, error) { ac.input = appconfig.GetConfigurationInput{ Application: &ac.config.Application, ClientId: &ac.config.ClientID, Configuration: &ac.config.Configuration, Environment: &ac.config.Environment, } if ac.config.ClientConfigurationVersion != "" { ac.input.ClientConfigurationVersion = &ac.config.ClientConfigurationVersion } conf, err := ac.client.GetConfiguration(context.TODO(), &ac.input) if err != nil { return nil, err } // Set the response configuration version as the current configuration version. // Useful for Watch(). ac.input.ClientConfigurationVersion = conf.ConfigurationVersion return conf.Content, nil } // Read is not supported by the appconfig provider. func (ac *AppConfig) Read() (map[string]interface{}, error) { return nil, errors.New("appconfig provider does not support this method") } // Watch polls AWS AppConfig for configuration updates. func (ac *AppConfig) Watch(cb func(event interface{}, err error)) error { if ac.config.WatchInterval == 0 { // Set default watch interval to 60 seconds. ac.config.WatchInterval = 60 * time.Second } go func() { loop: for { conf, err := ac.client.GetConfiguration(context.TODO(), &ac.input) if err != nil { cb(nil, err) break loop } // Check if the the configuration has been updated. if len(conf.Content) == 0 { // Configuration is not updated and we have the latest version. // Sleep for WatchInterval and retry watcher. time.Sleep(ac.config.WatchInterval) continue } // Trigger event. cb(nil, nil) } }() return nil } koanf-providers-vault-v2.0.1/providers/appconfig/go.mod000066400000000000000000000015341454017643500232470ustar00rootroot00000000000000module github.com/knadh/koanf/providers/appconfig/v2 go 1.18 require ( github.com/aws/aws-sdk-go-v2 v1.17.4 github.com/aws/aws-sdk-go-v2/config v1.18.12 github.com/aws/aws-sdk-go-v2/credentials v1.13.12 github.com/aws/aws-sdk-go-v2/service/appconfig v1.16.1 github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 ) require ( github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 // indirect github.com/aws/smithy-go v1.13.5 // indirect ) koanf-providers-vault-v2.0.1/providers/appconfig/go.sum000066400000000000000000000066441454017643500233030ustar00rootroot00000000000000github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY= github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/config v1.18.12 h1:fKs/I4wccmfrNRO9rdrbMO1NgLxct6H9rNMiPdBxHWw= github.com/aws/aws-sdk-go-v2/config v1.18.12/go.mod h1:J36fOhj1LQBr+O4hJCiT8FwVvieeoSGOtPuvhKlsNu8= github.com/aws/aws-sdk-go-v2/credentials v1.13.12 h1:Cb+HhuEnV19zHRaYYVglwvdHGMJWbdsyP4oHhw04xws= github.com/aws/aws-sdk-go-v2/credentials v1.13.12/go.mod h1:37HG2MBroXK3jXfxVGtbM2J48ra2+Ltu+tmwr/jO0KA= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 h1:3aMfcTmoXtTZnaT86QlVaYh+BRMbvrrmZwIQ5jWqCZQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 h1:r+XwaCLpIvCKjBIYy/HVZujQS9tsz5ohHG3ZIe0wKoE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKFmWoqpcOQJ4bH634SkYf3FNj/A= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s= github.com/aws/aws-sdk-go-v2/service/appconfig v1.16.1 h1:gbgUb8tvF7OWWZYvgtqdKsckZdtCblfidV5eBkjac30= github.com/aws/aws-sdk-go-v2/service/appconfig v1.16.1/go.mod h1:EGp7/CN7BQtPFYcfbTx06h3wZs/wkRp+8bcpyRmp+VU= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 h1:LjFQf8hFuMO22HkV5VWGLBvmCLBCLPivUAmpdpnp4Vs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws= github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 h1:lQKN/LNa3qqu2cDOQZybP7oL4nMGGiFqob0jZJaR8/4= github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 h1:0bLhH6DRAqox+g0LatcjGKjjhU6Eudyys6HB6DJVPj8= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k= github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 h1:s49mSnsBZEXjfGBkRfmK+nPqzT7Lt3+t2SmAKNyHblw= github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= koanf-providers-vault-v2.0.1/providers/basicflag/000077500000000000000000000000001454017643500221035ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/basicflag/basicflag.go000066400000000000000000000035631454017643500243540ustar00rootroot00000000000000// Package basicflag implements a koanf.Provider that reads commandline // parameters as conf maps using the Go's flag package. package basicflag import ( "errors" "flag" "github.com/knadh/koanf/maps" ) // Pflag implements a pflag command line provider. type Pflag struct { delim string flagset *flag.FlagSet cb func(key string, value string) (string, interface{}) } // Provider returns a commandline flags provider that returns // a nested map[string]interface{} of environment variable where the // nesting hierarchy of keys are defined by delim. For instance, the // delim "." will convert the key `parent.child.key: 1` // to `{parent: {child: {key: 1}}}`. func Provider(f *flag.FlagSet, delim string) *Pflag { return &Pflag{ flagset: f, delim: delim, } } // ProviderWithValue works exactly the same as Provider except the callback // takes a (key, value) with the variable name and value and allows you // to modify both. This is useful for cases where you may want to return // other types like a string slice instead of just a string. func ProviderWithValue(f *flag.FlagSet, delim string, cb func(key string, value string) (string, interface{})) *Pflag { return &Pflag{ flagset: f, delim: delim, cb: cb, } } // Read reads the flag variables and returns a nested conf map. func (p *Pflag) Read() (map[string]interface{}, error) { mp := make(map[string]interface{}) p.flagset.VisitAll(func(f *flag.Flag) { if p.cb != nil { key, value := p.cb(f.Name, f.Value.String()) // If the callback blanked the key, it should be omitted if key == "" { return } mp[key] = value } else { mp[f.Name] = f.Value.String() } }) return maps.Unflatten(mp, p.delim), nil } // ReadBytes is not supported by the basicflag koanf. func (p *Pflag) ReadBytes() ([]byte, error) { return nil, errors.New("basicflag provider does not support this method") } koanf-providers-vault-v2.0.1/providers/basicflag/go.mod000066400000000000000000000003401454017643500232060ustar00rootroot00000000000000module github.com/knadh/koanf/providers/basicflag go 1.18 require github.com/knadh/koanf/maps v0.1.1 require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect ) koanf-providers-vault-v2.0.1/providers/basicflag/go.sum000066400000000000000000000010371454017643500232370ustar00rootroot00000000000000github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= koanf-providers-vault-v2.0.1/providers/confmap/000077500000000000000000000000001454017643500216135ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/confmap/confmap.go000066400000000000000000000020151454017643500235630ustar00rootroot00000000000000// Package confmap implements a koanf.Provider that takes nested // and flat map[string]interface{} config maps and provides them // to koanf. package confmap import ( "errors" "github.com/knadh/koanf/maps" ) // Confmap implements a raw map[string]interface{} provider. type Confmap struct { mp map[string]interface{} } // Provider returns a confmap Provider that takes a flat or nested // map[string]interface{}. If a delim is provided, it indicates that the // keys are flat and the map needs to be unflatted by delim. func Provider(mp map[string]interface{}, delim string) *Confmap { cp := maps.Copy(mp) maps.IntfaceKeysToStrings(cp) if delim != "" { cp = maps.Unflatten(cp, delim) } return &Confmap{mp: cp} } // ReadBytes is not supported by the confmap provider. func (e *Confmap) ReadBytes() ([]byte, error) { return nil, errors.New("confmap provider does not support this method") } // Read returns the loaded map[string]interface{}. func (e *Confmap) Read() (map[string]interface{}, error) { return e.mp, nil } koanf-providers-vault-v2.0.1/providers/confmap/go.mod000066400000000000000000000003361454017643500227230ustar00rootroot00000000000000module github.com/knadh/koanf/providers/confmap go 1.18 require github.com/knadh/koanf/maps v0.1.1 require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect ) koanf-providers-vault-v2.0.1/providers/confmap/go.sum000066400000000000000000000010371454017643500227470ustar00rootroot00000000000000github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= koanf-providers-vault-v2.0.1/providers/consul/000077500000000000000000000000001454017643500214735ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/consul/consul.go000066400000000000000000000067551454017643500233420ustar00rootroot00000000000000package consul import ( "errors" "fmt" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api/watch" ) // Config represents the Consul client configuration. type Config struct { // Path of the key to read. If Recurse is true, this is treated // as a prefix. Key string // https://www.consul.io/api-docs/kv#read-key // If recurse is true, Consul returns an array of keys. // It specifies if the lookup should be recursive and treat // Key as a prefix instead of a literal match. // This is analogous to: consul kv get -recurse key Recurse bool // Gets additional metadata about the key in addition to the value such // as the ModifyIndex and any flags that may have been set on the key. // This is analogous to: consul kv get -detailed key Detailed bool // Consul client config Cfg *api.Config } // Consul implements the Consul provider. type Consul struct { client *api.Client cfg Config } // Provider returns an instance of the Consul provider. func Provider(cfg Config) (*Consul, error) { c, err := api.NewClient(cfg.Cfg) if err != nil { return nil, err } return &Consul{client: c, cfg: cfg}, nil } // ReadBytes is not supported by the Consul provider. func (c *Consul) ReadBytes() ([]byte, error) { return nil, errors.New("consul provider does not support this method") } // Read reads configuration from the Consul provider. func (c *Consul) Read() (map[string]interface{}, error) { var ( mp = make(map[string]interface{}) kv = c.client.KV() ) if c.cfg.Recurse { pairs, _, err := kv.List(c.cfg.Key, nil) if err != nil { return nil, err } // Detailed information can be obtained using standard koanf flattened delimited keys: // For example: // "parent1.CreateIndex" // "parent1.Flags" // "parent1.LockIndex" // "parent1.ModifyIndex" // "parent1.Session" // "parent1.Value" if c.cfg.Detailed { for _, pair := range pairs { m := make(map[string]interface{}) m["CreateIndex"] = fmt.Sprintf("%d", pair.CreateIndex) m["Flags"] = fmt.Sprintf("%d", pair.Flags) m["LockIndex"] = fmt.Sprintf("%d", pair.LockIndex) m["ModifyIndex"] = fmt.Sprintf("%d", pair.ModifyIndex) if pair.Session == "" { m["Session"] = "-" } else { m["Session"] = fmt.Sprintf("%s", pair.Session) } m["Value"] = string(pair.Value) mp[pair.Key] = m } } else { for _, pair := range pairs { mp[pair.Key] = string(pair.Value) } } return mp, nil } pair, _, err := kv.Get(c.cfg.Key, nil) if err != nil { return nil, err } if c.cfg.Detailed { m := make(map[string]interface{}) m["CreateIndex"] = fmt.Sprintf("%d", pair.CreateIndex) m["Flags"] = fmt.Sprintf("%d", pair.Flags) m["LockIndex"] = fmt.Sprintf("%d", pair.LockIndex) m["ModifyIndex"] = fmt.Sprintf("%d", pair.ModifyIndex) if pair.Session == "" { m["Session"] = "-" } else { m["Session"] = fmt.Sprintf("%s", pair.Session) } m["Value"] = string(pair.Value) mp[pair.Key] = m } else { mp[pair.Key] = string(pair.Value) } return mp, nil } // Watch watches for changes in the Consul API and triggers a callback. func (c *Consul) Watch(cb func(event interface{}, err error)) error { p := make(map[string]interface{}) if c.cfg.Recurse { p["type"] = "keyprefix" p["prefix"] = c.cfg.Key } else { p["type"] = "key" p["key"] = c.cfg.Key } plan, err := watch.Parse(p) if err != nil { return err } plan.Handler = func(_ uint64, val interface{}) { cb(val, nil) } go func() { plan.Run(c.cfg.Cfg.Address) }() return nil } koanf-providers-vault-v2.0.1/providers/consul/go.mod000066400000000000000000000014041454017643500226000ustar00rootroot00000000000000module github.com/knadh/koanf/providers/consul/v2 go 1.18 require github.com/hashicorp/consul/api v1.19.1 require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/fatih/color v1.14.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.4.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/serf v0.10.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect golang.org/x/sys v0.5.0 // indirect ) koanf-providers-vault-v2.0.1/providers/consul/go.sum000066400000000000000000000557271454017643500226460ustar00rootroot00000000000000github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= github.com/hashicorp/consul/api v1.19.1 h1:GLeK1WD4VIRvt4wRhQKHFudztEkRb8pDs+uRiJgNwes= github.com/hashicorp/consul/api v1.19.1/go.mod h1:jAt316eYgWGNLJtxkMQrcqRpuDE/kFJdqkEFwRXFv8U= github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/providers/env/000077500000000000000000000000001454017643500207605ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/env/env.go000066400000000000000000000052571454017643500221100ustar00rootroot00000000000000// Package env implements a koanf.Provider that reads environment // variables as conf maps. package env import ( "errors" "os" "strings" "github.com/knadh/koanf/maps" ) // Env implements an environment variables provider. type Env struct { prefix string delim string cb func(key string, value string) (string, interface{}) } // Provider returns an environment variables provider that returns // a nested map[string]interface{} of environment variable where the // nesting hierarchy of keys is defined by delim. For instance, the // delim "." will convert the key `parent.child.key: 1` // to `{parent: {child: {key: 1}}}`. // // If prefix is specified (case-sensitive), only the env vars with // the prefix are captured. cb is an optional callback that takes // a string and returns a string (the env variable name) in case // transformations have to be applied, for instance, to lowercase // everything, strip prefixes and replace _ with . etc. // If the callback returns an empty string, the variable will be // ignored. func Provider(prefix, delim string, cb func(s string) string) *Env { e := &Env{ prefix: prefix, delim: delim, } if cb != nil { e.cb = func(key string, value string) (string, interface{}) { return cb(key), value } } return e } // ProviderWithValue works exactly the same as Provider except the callback // takes a (key, value) with the variable name and value and allows you // to modify both. This is useful for cases where you may want to return // other types like a string slice instead of just a string. func ProviderWithValue(prefix, delim string, cb func(key string, value string) (string, interface{})) *Env { return &Env{ prefix: prefix, delim: delim, cb: cb, } } // 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) } } mp := make(map[string]interface{}) for _, k := range keys { parts := strings.SplitN(k, "=", 2) // If there's a transformation callback, // run it through every key/value. if e.cb != nil { key, value := e.cb(parts[0], parts[1]) // If the callback blanked the key, it should be omitted if key == "" { continue } mp[key] = value } else { mp[parts[0]] = parts[1] } } return maps.Unflatten(mp, e.delim), nil } koanf-providers-vault-v2.0.1/providers/env/env_test.go000066400000000000000000000124271454017643500231440ustar00rootroot00000000000000package env import ( "github.com/stretchr/testify/assert" "os" "strings" "testing" ) func TestProvider(t *testing.T) { testCases := []struct { name string prefix string delim string key string value string expKey string expValue string cb func(key string) string want *Env }{ { name: "Nil cb", prefix: "TESTVAR_", delim: ".", want: &Env{ prefix: "TESTVAR_", delim: ".", }, }, { name: "Simple cb", prefix: "TESTVAR_", delim: ".", key: "TestKey", value: "TestVal", expKey: "testkey", expValue: "TestVal", cb: func(key string) string { return strings.ToLower(key) }, want: &Env{ prefix: "TESTVAR_", delim: ".", }, }, { name: "Empty string nil cb", prefix: "", delim: ".", want: &Env{ prefix: "", delim: ".", }, }, { name: "Cb is given", prefix: "", delim: ".", key: "test_key", value: "test_val", expKey: "TEST.KEY", expValue: "test_val", cb: func(key string) string { return strings.Replace(strings.ToUpper(key), "_", ".", -1) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { gotProvider := Provider(tc.prefix, tc.delim, tc.cb) if tc.cb == nil { assert.Equal(t, tc.want, gotProvider) } if tc.cb != nil { k, v := gotProvider.cb(tc.key, tc.value) assert.Equal(t, tc.expKey, k) assert.Equal(t, tc.expValue, v) } }) } } func TestProviderWithValue(t *testing.T) { testCases := []struct { name string prefix string delim string cb func(key string, value string) (string, interface{}) nilCallback bool want *Env }{ { name: "Nil cb", prefix: "TEST_", delim: ".", nilCallback: true, want: &Env{ prefix: "TEST_", delim: ".", }, }, { name: "Empty string nil cb", prefix: "", delim: ".", nilCallback: true, want: &Env{ prefix: "", delim: ".", }, }, { name: "Return the same key-value pair in cb", prefix: "TEST_", delim: ".", cb: func(key string, value string) (string, interface{}) { return key, value }, want: &Env{ prefix: "TEST_", delim: ".", cb: func(key string, value string) (string, interface{}) { return key, value }, }, }, { name: "Custom cb function", prefix: "TEST_", delim: ".", cb: func(key string, value string) (string, interface{}) { key = strings.Replace(strings.TrimPrefix(strings.ToLower(key), "test_"), "_", ".", -1) return key, value }, want: &Env{ prefix: "TEST_", delim: ".", cb: func(key string, value string) (string, interface{}) { key = strings.Replace(strings.TrimPrefix(strings.ToLower(key), "test_"), "_", ".", -1) return key, value }, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { got := ProviderWithValue(tc.prefix, tc.delim, tc.cb) if tc.nilCallback { assert.Equal(t, tc.want, got) } else { keyGot, valGot := got.cb("test_key_env_1", "test_val") keyWant, valWant := tc.want.cb("test_key_env_1", "test_val") assert.Equal(t, tc.prefix, got.prefix) assert.Equal(t, tc.delim, got.delim) assert.Equal(t, keyWant, keyGot) assert.Equal(t, valWant, valGot) } }) } } func TestRead(t *testing.T) { testCases := []struct { name string key string value string expKey string expValue string env *Env }{ { name: "No cb", key: "TEST_KEY", value: "TEST_VAL", expKey: "TEST_KEY", expValue: "TEST_VAL", env: &Env{ delim: ".", }, }, { name: "cb given", key: "TEST_KEY", value: "TEST_VAL", expKey: "test.key", expValue: "TEST_VAL", env: &Env{ delim: "_", cb: func(key string, value string) (string, interface{}) { return strings.Replace(strings.ToLower(key), "_", ".", -1), value }, }, }, { name: "No cb - prefix given", key: "TEST_KEY", value: "TEST_VAL", expKey: "test.key", expValue: "TEST_VAL", env: &Env{ prefix: "TEST", delim: "/", cb: func(key string, value string) (string, interface{}) { return strings.Replace(strings.ToLower(key), "_", ".", -1), value }, }, }, { name: "Path value", key: "TEST_DIR", value: "/test/dir/file", expKey: "TEST_DIR", expValue: "/test/dir/file", env: &Env{ delim: ".", }, }, { name: "Replace value with underscore", key: "TEST_DIR", value: "/test/dir/file", expKey: "TEST_DIR", expValue: "_test_dir_file", env: &Env{ delim: ".", cb: func(key string, value string) (string, interface{}) { return key, strings.Replace(strings.ToLower(value), "/", "_", -1) }, }, }, { name: "Empty value", key: "KEY", value: "", expKey: "KEY", expValue: "", env: &Env{ delim: ".", }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := os.Setenv(tc.key, tc.value) assert.Nil(t, err) defer os.Unsetenv(tc.key) envs, err := tc.env.Read() assert.Nil(t, err) v, ok := envs[tc.expKey] assert.True(t, ok) assert.Equal(t, tc.expValue, v) }) } } koanf-providers-vault-v2.0.1/providers/env/go.mod000066400000000000000000000006111454017643500220640ustar00rootroot00000000000000module github.com/knadh/koanf/providers/env go 1.18 require ( github.com/knadh/koanf/maps v0.1.1 github.com/stretchr/testify v1.8.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/providers/env/go.sum000066400000000000000000000040151454017643500221130ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/providers/etcd/000077500000000000000000000000001454017643500211075ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/etcd/etcd.go000066400000000000000000000041111454017643500223520ustar00rootroot00000000000000package etcd import ( "context" "errors" "time" clientv3 "go.etcd.io/etcd/client/v3" ) type Config struct { // etcd endpoints Endpoints []string // timeout DialTimeout time.Duration // prefix request option Prefix bool // limit request option Limit bool // number of limited pairs NLimit int64 // key, key with prefix, etc. Key string } // Etcd implements the etcd config provider. type Etcd struct { client *clientv3.Client cfg Config } // Provider returns a provider that takes etcd config. func Provider(cfg Config) (*Etcd, error) { eCfg := clientv3.Config{ Endpoints: cfg.Endpoints, DialTimeout: cfg.DialTimeout, } c, err := clientv3.New(eCfg) if err != nil { return nil, err } return &Etcd{client: c, cfg: cfg}, nil } // ReadBytes is not supported by etcd provider. func (e *Etcd) ReadBytes() ([]byte, error) { return nil, errors.New("etcd provider does not support this method") } // Read returns a nested config map. func (e *Etcd) Read() (map[string]interface{}, error) { ctx, cancel := context.WithTimeout(context.Background(), e.cfg.DialTimeout) defer cancel() var resp *clientv3.GetResponse if e.cfg.Prefix { if e.cfg.Limit { r, err := e.client.Get(ctx, e.cfg.Key, clientv3.WithPrefix(), clientv3.WithLimit(e.cfg.NLimit)) if err != nil { return nil, err } resp = r } else { r, err := e.client.Get(ctx, e.cfg.Key, clientv3.WithPrefix()) if err != nil { return nil, err } resp = r } } else { r, err := e.client.Get(ctx, e.cfg.Key) if err != nil { return nil, err } resp = r } mp := make(map[string]interface{}, len(resp.Kvs)) for _, r := range resp.Kvs { mp[string(r.Key)] = string(r.Value) } return mp, nil } func (e *Etcd) Watch(cb func(event interface{}, err error)) error { var w clientv3.WatchChan go func() { if e.cfg.Prefix { w = e.client.Watch(context.Background(), e.cfg.Key, clientv3.WithPrefix()) } else { w = e.client.Watch(context.Background(), e.cfg.Key) } for wresp := range w { for _, ev := range wresp.Events { cb(ev, nil) } } }() return nil } koanf-providers-vault-v2.0.1/providers/etcd/go.mod000066400000000000000000000014371454017643500222220ustar00rootroot00000000000000module github.com/knadh/koanf/providers/etcd/v2 go 1.18 require go.etcd.io/etcd/client/v3 v3.5.7 require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.56.3 // indirect google.golang.org/protobuf v1.30.0 // indirect ) koanf-providers-vault-v2.0.1/providers/etcd/go.sum000066400000000000000000000154161454017643500222510ustar00rootroot00000000000000github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/providers/file/000077500000000000000000000000001454017643500211075ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/file/file.go000066400000000000000000000057371454017643500223710ustar00rootroot00000000000000// Package file implements a koanf.Provider that reads raw bytes // from files on disk to be used with a koanf.Parser to parse // into conf maps. package file import ( "errors" "fmt" "os" "path/filepath" "time" "github.com/fsnotify/fsnotify" ) // File implements a File provider. type File struct { path string } // Provider returns a file provider. func Provider(path string) *File { return &File{path: filepath.Clean(path)} } // ReadBytes reads the contents of a file on disk and returns the bytes. func (f *File) ReadBytes() ([]byte, error) { return os.ReadFile(f.path) } // Read is not supported by the file provider. func (f *File) Read() (map[string]interface{}, error) { return nil, errors.New("file provider does not support this method") } // Watch watches the file and triggers a callback when it changes. It is a // blocking function that internally spawns a goroutine to watch for changes. func (f *File) Watch(cb func(event interface{}, err error)) error { // Resolve symlinks and save the original path so that changes to symlinks // can be detected. realPath, err := filepath.EvalSymlinks(f.path) if err != nil { return err } realPath = filepath.Clean(realPath) // Although only a single file is being watched, fsnotify has to watch // the whole parent directory to pick up all events such as symlink changes. fDir, _ := filepath.Split(f.path) w, err := fsnotify.NewWatcher() if err != nil { return err } var ( lastEvent string lastEventTime time.Time ) go func() { loop: for { select { case event, ok := <-w.Events: if !ok { cb(nil, errors.New("fsnotify watch channel closed")) break loop } // Use a simple timer to buffer events as certain events fire // multiple times on some platforms. if event.String() == lastEvent && time.Since(lastEventTime) < time.Millisecond*5 { continue } lastEvent = event.String() lastEventTime = time.Now() evFile := filepath.Clean(event.Name) // Since the event is triggered on a directory, is this // one on the file being watched? if evFile != realPath && evFile != f.path { continue } // The file was removed. if event.Op&fsnotify.Remove != 0 { cb(nil, fmt.Errorf("file %s was removed", event.Name)) break loop } // Resolve symlink to get the real path, in case the symlink's // target has changed. curPath, err := filepath.EvalSymlinks(f.path) if err != nil { cb(nil, err) break loop } realPath = filepath.Clean(curPath) // Finally, we only care about create and write. if event.Op&(fsnotify.Write|fsnotify.Create) == 0 { continue } // Trigger event. cb(nil, nil) // There's an error. case err, ok := <-w.Errors: if !ok { cb(nil, errors.New("fsnotify err channel closed")) break loop } // Pass the error to the callback. cb(nil, err) break loop } } w.Close() }() // Watch the directory for changes. return w.Add(fDir) } koanf-providers-vault-v2.0.1/providers/file/go.mod000066400000000000000000000002541454017643500222160ustar00rootroot00000000000000module github.com/knadh/koanf/providers/file go 1.18 require github.com/fsnotify/fsnotify v1.6.0 require golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect koanf-providers-vault-v2.0.1/providers/file/go.sum000066400000000000000000000005761454017643500222520ustar00rootroot00000000000000github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= koanf-providers-vault-v2.0.1/providers/fs/000077500000000000000000000000001454017643500206005ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/fs/fs.go000066400000000000000000000015211454017643500215360ustar00rootroot00000000000000// Package fs implements a koanf.Provider that reads raw bytes // from given fs.FS to be used with a koanf.Parser to parse // into conf maps. //go:build go1.16 // +build go1.16 package fs import ( "errors" "io" "io/fs" ) // FS implements an fs.FS provider. type FS struct { fs fs.FS path string } // Provider returns an fs.FS provider. func Provider(fs fs.FS, filepath string) *FS { return &FS{fs: fs, path: filepath} } // ReadBytes reads the contents of given filepath from fs.FS and returns the bytes. func (f *FS) ReadBytes() ([]byte, error) { fd, err := f.fs.Open(f.path) if err != nil { return nil, err } defer fd.Close() return io.ReadAll(fd) } // Read is not supported by the fs.FS provider. func (f *FS) Read() (map[string]interface{}, error) { return nil, errors.New("fs.FS provider does not support this method") } koanf-providers-vault-v2.0.1/providers/fs/go.mod000066400000000000000000000000641454017643500217060ustar00rootroot00000000000000module github.com/knadh/koanf/providers/fs go 1.18 koanf-providers-vault-v2.0.1/providers/nats/000077500000000000000000000000001454017643500211355ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/nats/go.mod000066400000000000000000000021471454017643500222470ustar00rootroot00000000000000module github.com/knadh/koanf/providers/nats go 1.18 require ( github.com/knadh/koanf/v2 v2.0.0 github.com/nats-io/nats-server/v2 v2.9.23 github.com/nats-io/nats.go v1.28.0 github.com/stretchr/testify v1.8.2 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/nats-io/jwt/v2 v2.5.0 // indirect github.com/nats-io/nkeys v0.4.6 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/providers/nats/go.sum000066400000000000000000000126201454017643500222710ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/v2 v2.0.0 h1:XPQ5ilNnwnNaHrfQ1YpTVhUAjcGHnEKA+lRpipQv02Y= github.com/knadh/koanf/v2 v2.0.0/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak= github.com/nats-io/jwt/v2 v2.5.0/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI= github.com/nats-io/nats-server/v2 v2.9.23 h1:6Wj6H6QpP9FMlpCyWUaNu2yeZ/qGj+mdRkZ1wbikExU= github.com/nats-io/nats-server/v2 v2.9.23/go.mod h1:wEjrEy9vnqIGE4Pqz4/c75v9Pmaq7My2IgFmnykc4C0= github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c= github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc= github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY= github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/providers/nats/nats.go000066400000000000000000000037231454017643500224360ustar00rootroot00000000000000package nats import ( "errors" "fmt" "strings" "time" "github.com/nats-io/nats.go" ) type Config struct { // nats endpoint (comma separated urls are possible, eg "nats://one, nats://two"). URL string // Optional NATS options: nats.Connect(url, ...options) Options []nats.Option // Optional JetStream options: nc.JetStream(...options) JetStreamOptions []nats.JSOpt // Bucket is the Nats KV bucket. Bucket string // Prefix (optional). Prefix string } // Nats implements the nats config provider. type Nats struct { kv nats.KeyValue cfg Config } // Provider returns a provider that takes nats config. func Provider(cfg Config) (*Nats, error) { nc, err := nats.Connect(cfg.URL, cfg.Options...) if err != nil { return nil, err } js, err := nc.JetStream(cfg.JetStreamOptions...) if err != nil { return nil, err } kv, err := js.KeyValue(cfg.Bucket) if err != nil { return nil, err } return &Nats{kv: kv, cfg: cfg}, nil } // ReadBytes is not supported by nats provider. func (n *Nats) ReadBytes() ([]byte, error) { return nil, errors.New("nats provider does not support this method") } // Read returns a nested config map. func (n *Nats) Read() (map[string]interface{}, error) { keys, err := n.kv.Keys() if err != nil { return nil, err } mp := make(map[string]interface{}) for _, key := range keys { if !strings.HasPrefix(key, n.cfg.Prefix) { continue } res, err := n.kv.Get(key) if err != nil { return nil, err } mp[res.Key()] = string(res.Value()) } return mp, nil } func (n *Nats) Watch(cb func(event interface{}, err error)) error { w, err := n.kv.Watch(fmt.Sprintf("%s.*", n.cfg.Prefix)) if err != nil { return err } start := time.Now() go func(watcher nats.KeyWatcher) { for update := range watcher.Updates() { // ignore nil events and only callback when the event is new (nats always sends one "old" event) if update != nil && update.Created().After(start) { cb(update, nil) } } }(w) return nil } koanf-providers-vault-v2.0.1/providers/nats/nats_test.go000066400000000000000000000023541454017643500234740ustar00rootroot00000000000000package nats import ( "testing" "time" "github.com/knadh/koanf/v2" "github.com/nats-io/nats.go" "github.com/stretchr/testify/assert" ) func TestNats(t *testing.T) { k := koanf.NewWithConf(koanf.Conf{}) nc, err := nats.Connect(testNatsURL) if err != nil { t.Fatal(err) } defer nc.Drain() js, err := nc.JetStream() if err != nil { t.Fatal(err) } kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: "test", }) _, err = kv.Put("some.test.color", []byte("blue")) if err != nil { t.Fatal(err) } provider, err := Provider(Config{ URL: testNatsURL, Bucket: "test", Prefix: "some.test", }) if err != nil { t.Fatal(err) } err = k.Load(provider, nil) if err != nil { t.Fatal(err) } assert.Equal(t, k.Keys(), []string{"some.test.color"}) assert.Equal(t, k.Get("some.test.color"), "blue") err = provider.Watch(func(event interface{}, err error) { if err != nil { t.Fatal(err) } err = k.Load(provider, nil) if err != nil { t.Fatal(err) } }) if err != nil { t.Fatal(err) } go func() { _, err := kv.Put("some.test.color", []byte("yellow")) if err != nil { t.Error(err) return } }() time.Sleep(100 * time.Millisecond) assert.Equal(t, k.Get("some.test.color"), "yellow") } koanf-providers-vault-v2.0.1/providers/nats/testrunner_test.go000066400000000000000000000012561454017643500247400ustar00rootroot00000000000000package nats import ( "log" "os" "testing" "time" "github.com/nats-io/nats-server/v2/logger" "github.com/nats-io/nats-server/v2/server" ) var testNatsURL string func TestMain(m *testing.M) { gnatsd, err := server.NewServer(&server.Options{ Port: server.RANDOM_PORT, JetStream: true, }) if err != nil { log.Fatal("failed to create gnatsd server") } gnatsd.SetLogger( logger.NewStdLogger(false, false, false, false, false), false, false, ) go gnatsd.Start() defer gnatsd.Shutdown() if !gnatsd.ReadyForConnections(time.Second) { log.Fatal("failed to start the gnatsd server") } testNatsURL = "nats://" + gnatsd.Addr().String() os.Exit(m.Run()) } koanf-providers-vault-v2.0.1/providers/parameterstore/000077500000000000000000000000001454017643500232255ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/parameterstore/go.mod000066400000000000000000000024551454017643500243410ustar00rootroot00000000000000module github.com/knadh/koanf/providers/parameterstore/v2 go 1.18 require ( github.com/aws/aws-sdk-go-v2 v1.21.0 github.com/aws/aws-sdk-go-v2/config v1.18.37 github.com/aws/aws-sdk-go-v2/service/ssm v1.37.5 github.com/aws/smithy-go v1.14.2 github.com/knadh/koanf/maps v0.1.1 github.com/knadh/koanf/v2 v2.0.1 github.com/stretchr/testify v1.8.4 ) require ( github.com/aws/aws-sdk-go-v2/credentials v1.13.35 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/providers/parameterstore/go.sum000066400000000000000000000123111454017643500243560ustar00rootroot00000000000000github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= github.com/aws/aws-sdk-go-v2/config v1.18.37 h1:RNAfbPqw1CstCooHaTPhScz7z1PyocQj0UL+l95CgzI= github.com/aws/aws-sdk-go-v2/config v1.18.37/go.mod h1:8AnEFxW9/XGKCbjYDCJy7iltVNyEI9Iu9qC21UzhhgQ= github.com/aws/aws-sdk-go-v2/credentials v1.13.35 h1:QpsNitYJu0GgvMBLUIYu9H4yryA5kMksjeIVQfgXrt8= github.com/aws/aws-sdk-go-v2/credentials v1.13.35/go.mod h1:o7rCaLtvK0hUggAGclf76mNGGkaG5a9KWlp+d9IpcV8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= github.com/aws/aws-sdk-go-v2/service/ssm v1.37.5 h1:s9QR0F1W5+11lq04OJ/mihpRpA2VDFIHmu+ktgAbNfg= github.com/aws/aws-sdk-go-v2/service/ssm v1.37.5/go.mod h1:JjBzoceyKkpQY3v1GPIdg6kHqUFHRJ7SDlwtwoH0Qh8= github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 h1:oCvTFSDi67AX0pOX3PuPdGFewvLRU2zzFSrTsgURNo0= github.com/aws/aws-sdk-go-v2/service/sso v1.13.5/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 h1:dnInJb4S0oy8aQuri1mV6ipLlnZPfnsDNB9BGO9PDNY= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ= github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/providers/parameterstore/parameterstore.go000066400000000000000000000104141454017643500266110ustar00rootroot00000000000000// Package parameterstore implements a koanf.Provider for AWS Systems Manager Parameter Store. package parameterstore import ( "context" "errors" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/knadh/koanf/maps" ) // Input is a constraint that permits any input type // to get paramers from AWS Systems Manager Parameter Store. type Input interface { ssm.GetParameterInput | ssm.GetParametersInput | ssm.GetParametersByPathInput } // Config represents a ParameterStore provider configuration. type Config[T Input] struct { // Delim is the delimiter to use // when specifying config key paths, for instance a . for `parent.child.key` // or a / for `parent/child/key`. Delim string // Input is the input to get parameters. Input T // OptFns is the additional functional options to get parameters. OptFns []func(*ssm.Options) // Callback is an optional callback that takes a (key, value) // with the variable name and value and allows you to modify both. // If the callback returns an empty key, the variable will be ignored. Callback func(key, value string) (string, interface{}) } // ParameterStore implements an AWS Systems Manager Parameter Store provider. type ParameterStore[T Input] struct { client *ssm.Client config Config[T] } // Provider returns a ParameterStore provider. // The AWS Systems Manager Client is configured via environment variables. // The configuration values are read from the environment variables. // - AWS_REGION // - AWS_ACCESS_KEY_ID // - AWS_SECRET_ACCESS_KEY // - AWS_SESSION_TOKEN func Provider[T Input](config Config[T]) (*ParameterStore[T], error) { c, err := awsconfig.LoadDefaultConfig(context.TODO()) if err != nil { return nil, err } return ProviderWithClient[T](config, ssm.NewFromConfig(c)), nil } // ProviderWithClient returns a ParameterStore provider // using an existing AWS Systems Manager client. func ProviderWithClient[T Input](config Config[T], client *ssm.Client) *ParameterStore[T] { return &ParameterStore[T]{ client: client, config: config, } } // ReadBytes is not supported by the ParameterStore provider. func (ps *ParameterStore[T]) ReadBytes() ([]byte, error) { return nil, errors.New("parameterstore provider does not support this method") } // Read returns a nested config map. func (ps *ParameterStore[T]) Read() (map[string]interface{}, error) { var ( mp = make(map[string]interface{}) ) switch input := interface{}(ps.config.Input).(type) { case ssm.GetParameterInput: output, err := ps.client.GetParameter(context.TODO(), &input, ps.config.OptFns...) if err != nil { return nil, err } // If there's a transformation callback, run it. if ps.config.Callback != nil { name, value := ps.config.Callback(*output.Parameter.Name, *output.Parameter.Value) // If the callback blanked the key, it should be omitted. if name == "" { break } mp[name] = value } else { mp[*output.Parameter.Name] = *output.Parameter.Value } case ssm.GetParametersInput: output, err := ps.client.GetParameters(context.TODO(), &input, ps.config.OptFns...) if err != nil { return nil, err } for _, p := range output.Parameters { // If there's a transformation callback, run it. if ps.config.Callback != nil { name, value := ps.config.Callback(*p.Name, *p.Value) // If the callback blanked the key, it should be omitted. if name == "" { break } mp[name] = value } else { mp[*p.Name] = *p.Value } } case ssm.GetParametersByPathInput: var nextToken *string for { input.NextToken = nextToken output, err := ps.client.GetParametersByPath(context.TODO(), &input, ps.config.OptFns...) if err != nil { return nil, err } for _, p := range output.Parameters { // If there's a transformation callback, run it. if ps.config.Callback != nil { name, value := ps.config.Callback(*p.Name, *p.Value) // If the callback blanked the key, it should be omitted. if name == "" { break } mp[name] = value } else { mp[*p.Name] = *p.Value } } if output.NextToken == nil { break } nextToken = output.NextToken } } // Unflatten only when a delimiter is specified. if ps.config.Delim != "" { mp = maps.Unflatten(mp, ps.config.Delim) } return mp, nil } koanf-providers-vault-v2.0.1/providers/parameterstore/parameterstore_test.go000066400000000000000000000150451454017643500276550ustar00rootroot00000000000000package parameterstore import ( "context" "strings" "testing" "github.com/aws/aws-sdk-go-v2/aws" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/aws/smithy-go/middleware" "github.com/knadh/koanf/v2" "github.com/stretchr/testify/assert" ) func TestParameterStore(t *testing.T) { c, err := config.LoadDefaultConfig( context.TODO(), config.WithRegion("us-east-1"), config.WithAPIOptions([]func(*middleware.Stack) error{ // Mock the SDK response using the middleware. func(stack *middleware.Stack) error { type key struct{} err := stack.Initialize.Add( middleware.InitializeMiddlewareFunc( "MockInitialize", func(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) (out middleware.InitializeOutput, metadata middleware.Metadata, err error) { switch v := in.Parameters.(type) { case *ssm.GetParametersByPathInput: ctx = middleware.WithStackValue(ctx, key{}, v.NextToken) } return next.HandleInitialize(ctx, in) }, ), middleware.Before, ) if err != nil { return err } return stack.Finalize.Add( middleware.FinalizeMiddlewareFunc( "MockFinalize", func(ctx context.Context, input middleware.FinalizeInput, handler middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { switch awsmiddleware.GetOperationName(ctx) { case "GetParameter": return middleware.FinalizeOutput{ Result: &ssm.GetParameterOutput{ Parameter: &types.Parameter{ Name: aws.String("prefix.parent1"), Value: aws.String("alice"), }, }, }, middleware.Metadata{}, nil case "GetParameters": return middleware.FinalizeOutput{ Result: &ssm.GetParametersOutput{ Parameters: []types.Parameter{ { Name: aws.String("prefix.parent1"), Value: aws.String("alice"), }, { Name: aws.String("prefix.parent2.child1"), Value: aws.String("bob"), }, }, }, }, middleware.Metadata{}, nil case "GetParametersByPath": var output ssm.GetParametersByPathOutput if middleware.GetStackValue(ctx, key{}) == (*string)(nil) { output = ssm.GetParametersByPathOutput{ NextToken: aws.String("nextToken"), Parameters: []types.Parameter{ { Name: aws.String("prefix.parent1"), Value: aws.String("alice"), }, { Name: aws.String("prefix.parent2.child1"), Value: aws.String("bob"), }, }, } } else { output = ssm.GetParametersByPathOutput{ Parameters: []types.Parameter{ { Name: aws.String("prefix.parent2.child2.grandchild1"), Value: aws.String("carol"), }, }, } } return middleware.FinalizeOutput{Result: &output}, middleware.Metadata{}, nil default: return middleware.FinalizeOutput{}, middleware.Metadata{}, nil } }, ), middleware.Before, ) }, }), ) assert.NoError(t, err) client := ssm.NewFromConfig(c) tests := map[string]struct { provider koanf.Provider want map[string]interface{} }{ "get a parameter": { provider: ProviderWithClient(Config[ssm.GetParameterInput]{ Delim: ".", Input: ssm.GetParameterInput{Name: aws.String("parent1")}, Callback: func(key, value string) (string, interface{}) { return strings.TrimPrefix(key, "prefix."), value }, }, client), want: map[string]interface{}{ "parent1": "alice", }, }, "get parameters": { provider: ProviderWithClient(Config[ssm.GetParametersInput]{ Delim: ".", Input: ssm.GetParametersInput{Names: []string{"parent1", "parent2.child1"}}, Callback: func(key, value string) (string, interface{}) { return strings.TrimPrefix(key, "prefix."), value }, }, client), want: map[string]interface{}{ "parent1": "alice", "parent2": map[string]interface{}{ "child1": "bob", }, }, }, "get parameters by path": { provider: ProviderWithClient(Config[ssm.GetParametersByPathInput]{ Delim: ".", Input: ssm.GetParametersByPathInput{Path: aws.String("/")}, Callback: func(key, value string) (string, interface{}) { return strings.TrimPrefix(key, "prefix."), value }, }, client), want: map[string]interface{}{ "parent1": "alice", "parent2": map[string]interface{}{ "child1": "bob", "child2": map[string]interface{}{ "grandchild1": "carol", }, }, }, }, "get a parameter but it is ignored": { provider: ProviderWithClient(Config[ssm.GetParameterInput]{ Delim: ".", Input: ssm.GetParameterInput{Name: aws.String("parent1")}, Callback: func(key, value string) (string, interface{}) { return strings.TrimPrefix(strings.TrimPrefix(key, "prefix."), "parent1"), value }, }, client), want: map[string]interface{}{ // Ignored. // "parent1": "alice", }, }, "get parameters but one is ignored": { provider: ProviderWithClient(Config[ssm.GetParametersInput]{ Delim: ".", Input: ssm.GetParametersInput{Names: []string{"parent1", "parent2.child1"}}, Callback: func(key, value string) (string, interface{}) { return strings.TrimPrefix(strings.TrimPrefix(key, "prefix."), "parent2.child1"), value }, }, client), want: map[string]interface{}{ "parent1": "alice", // Ignored. // "parent2": map[string]interface{}{ // "child1": "bob", // }, }, }, "get parameters by path but ont is ignored": { provider: ProviderWithClient(Config[ssm.GetParametersByPathInput]{ Delim: ".", Input: ssm.GetParametersByPathInput{Path: aws.String("/")}, Callback: func(key, value string) (string, interface{}) { return strings.TrimPrefix(strings.TrimPrefix(key, "prefix."), "parent2.child2.grandchild1"), value }, }, client), want: map[string]interface{}{ "parent1": "alice", "parent2": map[string]interface{}{ "child1": "bob", // Ignored. // "child2": map[string]interface{}{ // "grandchild1": "carol", // }, }, }, }, } for name, test := range tests { test := test t.Run(name, func(t *testing.T) { got, err := test.provider.Read() assert.NoError(t, err) assert.Equal(t, test.want, got) }) } } koanf-providers-vault-v2.0.1/providers/posflag/000077500000000000000000000000001454017643500216235ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/posflag/go.mod000066400000000000000000000004021454017643500227250ustar00rootroot00000000000000module github.com/knadh/koanf/providers/posflag go 1.18 require ( github.com/knadh/koanf/maps v0.1.1 github.com/spf13/pflag v1.0.5 ) require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect ) koanf-providers-vault-v2.0.1/providers/posflag/go.sum000066400000000000000000000013021454017643500227520ustar00rootroot00000000000000github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= koanf-providers-vault-v2.0.1/providers/posflag/posflag.go000066400000000000000000000153461454017643500236160ustar00rootroot00000000000000// Package posflag implements a koanf.Provider that reads commandline // parameters as conf maps using spf13/pflag, a POSIX compliant // alternative to Go's stdlib flag package. package posflag import ( "errors" "github.com/knadh/koanf/maps" "github.com/spf13/pflag" ) // KoanfIntf is an interface that represents a small subset of methods // used by this package from Koanf{}. When using this package, a live // instance of Koanf{} should be passed. type KoanfIntf interface { Exists(string) bool } // Posflag implements a pflag command line provider. type Posflag struct { delim string flagset *pflag.FlagSet ko KoanfIntf cb func(key string, value string) (string, interface{}) flagCB func(f *pflag.Flag) (string, interface{}) } // Provider returns a commandline flags provider that returns // a nested map[string]interface{} of environment variable where the // nesting hierarchy of keys are defined by delim. For instance, the // delim "." will convert the key `parent.child.key: 1` // to `{parent: {child: {key: 1}}}`. // // It takes an optional (but recommended) Koanf instance to see if the // the flags defined have been set from other providers, for instance, // a config file. If they are not, then the default values of the flags // are merged. If they do exist, the flag values are not merged but only // the values that have been explicitly set in the command line are merged. func Provider(f *pflag.FlagSet, delim string, ko KoanfIntf) *Posflag { return &Posflag{ flagset: f, delim: delim, ko: ko, } } // ProviderWithValue works exactly the same as Provider except the callback // takes a (key, value) with the variable name and value and allows their modification. // This is useful for cases where complex types like slices separated by // custom separators. // Returning "" for the key causes the particular flag to be disregarded. func ProviderWithValue(f *pflag.FlagSet, delim string, ko KoanfIntf, cb func(key string, value string) (string, interface{})) *Posflag { return &Posflag{ flagset: f, delim: delim, ko: ko, cb: cb, } } // ProviderWithFlag takes pflag.FlagSet and a callback that takes *pflag.Flag // and applies the callback to all items in the flagset. It does not parse // pflag.Flag values and expects the callback to process the keys and values // from *pflag.Flag however. FlagVal() can be used in the callbakc to avoid // repeating the type-switch block for parsing values. // Returning "" for the key causes the particular flag to be disregarded. // // Example: // // p := posflag.ProviderWithFlag(flagset, ".", ko, func(f *pflag.Flag) (string, interface{}) { // // Transform the key in whatever manner. // key := f.Name // // // Use FlagVal() and then transform the value, or don't use it at all // // and add custom logic to parse the value. // val := posflag.FlagVal(flagset, f) // // return key, val // }) func ProviderWithFlag(f *pflag.FlagSet, delim string, ko KoanfIntf, cb func(f *pflag.Flag) (string, interface{})) *Posflag { return &Posflag{ flagset: f, delim: delim, ko: ko, flagCB: cb, } } // Read reads the flag variables and returns a nested conf map. func (p *Posflag) Read() (map[string]interface{}, error) { mp := make(map[string]interface{}) p.flagset.VisitAll(func(f *pflag.Flag) { var ( key = f.Name val interface{} ) // If there is a (key, value) callback set, pass the key and string // value from the flagset to it and use the results. if p.cb != nil { key, val = p.cb(key, f.Value.String()) } else if p.flagCB != nil { // If there is a pflag.Flag callback set, pass the flag as-is // to it and use the results from the callback. key, val = p.flagCB(f) } else { // There are no callbacks set. Use the in-built flag value parser. val = FlagVal(p.flagset, f) } if key == "" { return } // If the default value of the flag was never changed by the user, // it should not override the value in the conf map (if it exists in the first place). if !f.Changed { if p.ko != nil { if p.ko.Exists(key) { return } } else { return } } // No callback. Use the key and value as-is. mp[key] = val }) return maps.Unflatten(mp, p.delim), nil } // ReadBytes is not supported by the pflag provider. func (p *Posflag) ReadBytes() ([]byte, error) { return nil, errors.New("pflag provider does not support this method") } // Watch is not supported. func (p *Posflag) Watch(cb func(event interface{}, err error)) error { return errors.New("posflag provider does not support this method") } // FlagVal examines a pflag.Flag and returns a typed value as an interface{} // from the types that pflag supports. If it is of a type that isn't known // for any reason, the value is returned as a string. func FlagVal(fs *pflag.FlagSet, f *pflag.Flag) interface{} { var ( key = f.Name val interface{} ) switch f.Value.Type() { case "int": i, _ := fs.GetInt(key) val = int64(i) case "uint": i, _ := fs.GetUint(key) val = uint64(i) case "int8": i, _ := fs.GetInt8(key) val = int64(i) case "uint8": i, _ := fs.GetUint8(key) val = uint64(i) case "int16": i, _ := fs.GetInt16(key) val = int64(i) case "uint16": i, _ := fs.GetUint16(key) val = uint64(i) case "int32": i, _ := fs.GetInt32(key) val = int64(i) case "uint32": i, _ := fs.GetUint32(key) val = uint64(i) case "int64": val, _ = fs.GetInt64(key) case "uint64": val, _ = fs.GetUint64(key) case "float": val, _ = fs.GetFloat64(key) case "float32": val, _ = fs.GetFloat32(key) case "float64": val, _ = fs.GetFloat64(key) case "bool": val, _ = fs.GetBool(key) case "duration": val, _ = fs.GetDuration(key) case "ip": val, _ = fs.GetIP(key) case "ipMask": val, _ = fs.GetIPv4Mask(key) case "ipNet": val, _ = fs.GetIPNet(key) case "count": val, _ = fs.GetCount(key) case "bytesHex": val, _ = fs.GetBytesHex(key) case "bytesBase64": val, _ = fs.GetBytesBase64(key) case "string": val, _ = fs.GetString(key) case "stringSlice": val, _ = fs.GetStringSlice(key) case "intSlice": val, _ = fs.GetIntSlice(key) case "uintSlice": val, _ = fs.GetUintSlice(key) case "int32Slice": val, _ = fs.GetInt32Slice(key) case "int64Slice": val, _ = fs.GetInt64Slice(key) case "float32Slice": val, _ = fs.GetFloat32Slice(key) case "float64Slice": val, _ = fs.GetFloat64Slice(key) case "boolSlice": val, _ = fs.GetBoolSlice(key) case "durationSlice": val, _ = fs.GetDurationSlice(key) case "ipSlice": val, _ = fs.GetIPSlice(key) case "stringArray": val, _ = fs.GetStringArray(key) case "stringToString": val, _ = fs.GetStringToString(key) case "stringToInt": val, _ = fs.GetStringToInt(key) case "stringToInt64": val, _ = fs.GetStringToInt64(key) default: val = f.Value.String() } return val } koanf-providers-vault-v2.0.1/providers/rawbytes/000077500000000000000000000000001454017643500220305ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/rawbytes/go.mod000066400000000000000000000000721454017643500231350ustar00rootroot00000000000000module github.com/knadh/koanf/providers/rawbytes go 1.18 koanf-providers-vault-v2.0.1/providers/rawbytes/rawbytes.go000066400000000000000000000015171454017643500242230ustar00rootroot00000000000000// Package rawbytes implements a koanf.Provider that takes a []byte slice // and provides it to koanf to be parsed by a koanf.Parser. package rawbytes import ( "errors" ) // RawBytes implements a raw bytes provider. type RawBytes struct { b []byte } // Provider returns a provider that takes a raw []byte slice to be parsed // by a koanf.Parser parser. This should be a nested conf map, like the // contents of a raw JSON config file. func Provider(b []byte) *RawBytes { r := &RawBytes{b: make([]byte, len(b))} copy(r.b[:], b) return r } // ReadBytes returns the raw bytes for parsing. func (r *RawBytes) ReadBytes() ([]byte, error) { return r.b, nil } // Read is not supported by rawbytes provider. func (r *RawBytes) Read() (map[string]interface{}, error) { return nil, errors.New("rawbytes provider does not support this method") } koanf-providers-vault-v2.0.1/providers/s3/000077500000000000000000000000001454017643500205155ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/s3/go.mod000066400000000000000000000001371454017643500216240ustar00rootroot00000000000000module github.com/knadh/koanf/providers/s3 go 1.18 require github.com/rhnvrm/simples3 v0.8.3 koanf-providers-vault-v2.0.1/providers/s3/go.sum000066400000000000000000000002531454017643500216500ustar00rootroot00000000000000github.com/rhnvrm/simples3 v0.8.3 h1:6dS0EE/hMIkaJd9gJOoXZOwtQQqI4NJyk0jvtl86n28= github.com/rhnvrm/simples3 v0.8.3/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= koanf-providers-vault-v2.0.1/providers/s3/s3.go000066400000000000000000000024661454017643500214010ustar00rootroot00000000000000// Package s3 implements a koanf.Provider that takes a []byte slice // and provides it to koanf to be parsed by a koanf.Parser. package s3 import ( "errors" "io" "github.com/rhnvrm/simples3" ) // Config for the provider. type Config struct { // AWS Access Key AccessKey string // AWS Secret Key SecretKey string // AWS region Region string // Bucket Name Bucket string // Object Key ObjectKey string // Optional: Custom S3 compatible endpoint Endpoint string } // S3 implements a s3 provider. type S3 struct { s3 *simples3.S3 cfg Config } // Provider returns a provider that takes a simples3 config. func Provider(cfg Config) *S3 { s3 := simples3.New(cfg.Region, cfg.AccessKey, cfg.SecretKey) s3.SetEndpoint(cfg.Endpoint) return &S3{s3: s3, cfg: cfg} } // ReadBytes reads the contents of a file on s3 and returns the bytes. func (r *S3) ReadBytes() ([]byte, error) { resp, err := r.s3.FileDownload(simples3.DownloadInput{ Bucket: r.cfg.Bucket, ObjectKey: r.cfg.ObjectKey, }) if err != nil { return nil, err } defer resp.Close() data, err := io.ReadAll(resp) if err != nil { return nil, err } return data, nil } // Read is not supported for s3 provider. func (r *S3) Read() (map[string]interface{}, error) { return nil, errors.New("s3 provider does not support this method") } koanf-providers-vault-v2.0.1/providers/structs/000077500000000000000000000000001454017643500216775ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/structs/go.mod000066400000000000000000000004041454017643500230030ustar00rootroot00000000000000module github.com/knadh/koanf/providers/structs go 1.18 require ( github.com/fatih/structs v1.1.0 github.com/knadh/koanf/maps v0.1.1 ) require ( github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect ) koanf-providers-vault-v2.0.1/providers/structs/go.sum000066400000000000000000000013061454017643500230320ustar00rootroot00000000000000github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= koanf-providers-vault-v2.0.1/providers/structs/structs.go000066400000000000000000000024171454017643500237410ustar00rootroot00000000000000// Package structs implements a koanf.Provider that takes a struct and tag // and returns a nested config map (using fatih/structs) to provide it to koanf. package structs import ( "errors" "github.com/fatih/structs" "github.com/knadh/koanf/maps" ) // Structs implements a structs provider. type Structs struct { s interface{} tag string delim string } // Provider returns a provider that takes a takes a struct and a struct tag // and uses structs to parse and provide it to koanf. func Provider(s interface{}, tag string) *Structs { return &Structs{s: s, tag: tag} } // ProviderWithDelim returns a provider that takes a struct and a struct tag // along with a delim and uses structs to parse and provide it to koanf. func ProviderWithDelim(s interface{}, tag, delim string) *Structs { return &Structs{s: s, tag: tag, delim: delim} } // ReadBytes is not supported by the structs provider. func (s *Structs) ReadBytes() ([]byte, error) { return nil, errors.New("structs provider does not support this method") } // Read reads the struct and returns a nested config map. func (s *Structs) Read() (map[string]interface{}, error) { ns := structs.New(s.s) ns.TagName = s.tag out := ns.Map() if s.delim != "" { out = maps.Unflatten(out, s.delim) } return out, nil } koanf-providers-vault-v2.0.1/providers/structs/structs_test.go000066400000000000000000000053631454017643500250030ustar00rootroot00000000000000package structs import ( "reflect" "testing" ) type parentStruct struct { Name string `koanf:"name"` ID int `koanf:"id"` Child1 childStruct `koanf:"child1"` } type childStruct struct { Name string `koanf:"name"` Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Grandchild1 grandchildStruct `koanf:"grandchild1"` } type grandchildStruct struct { Ids []int `koanf:"ids"` On bool `koanf:"on"` } type testStruct struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1 parentStruct `koanf:"parent1"` } type testStructWithDelim struct { Endpoint string `koanf:"conf_endpoint"` Username string `koanf:"conf_creds.username"` Password string `koanf:"conf_creds.password"` } func TestStructs_Read(t *testing.T) { type fields struct { s interface{} tag string delim string } tests := []struct { name string fields fields want map[string]interface{} wantErr bool }{ { name: "read", fields: fields{ s: testStruct{ Type: "json", Empty: make(map[string]string), Parent1: parentStruct{ Name: "parent1", ID: 1234, Child1: childStruct{ Name: "child1", Type: "json", Empty: make(map[string]string), Grandchild1: grandchildStruct{ Ids: []int{1, 2, 3}, On: true, }, }, }, }, tag: "koanf", }, want: map[string]interface{}{ "type": "json", "empty": map[string]string{}, "parent1": map[string]interface{}{ "child1": map[string]interface{}{ "empty": map[string]string{}, "type": "json", "name": "child1", "grandchild1": map[string]interface{}{ "on": true, "ids": []int{1, 2, 3}, }, }, "name": "parent1", "id": 1234, }, }, wantErr: false, }, { name: "read delim struct", fields: fields{ s: testStructWithDelim{ Endpoint: "test_endpoint", Username: "test_username", Password: "test_password", }, tag: "koanf", delim: ".", }, want: map[string]interface{}{ "conf_creds": map[string]interface{}{ "password": "test_password", "username": "test_username", }, "conf_endpoint": "test_endpoint", }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &Structs{ s: tt.fields.s, tag: tt.fields.tag, delim: tt.fields.delim, } got, err := s.Read() if (err != nil) != tt.wantErr { t.Errorf("Structs.Read() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("Structs.Read() = \n%#v\nwant \n%#v\n", got, tt.want) } }) } } koanf-providers-vault-v2.0.1/providers/vault/000077500000000000000000000000001454017643500213235ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/providers/vault/go.mod000066400000000000000000000026671454017643500224440ustar00rootroot00000000000000module github.com/knadh/koanf/providers/vault/v2 go 1.18 require ( github.com/hashicorp/vault/api v1.9.0 github.com/knadh/koanf/maps v0.1.1 ) require ( github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/fatih/color v1.14.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.4.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/stretchr/testify v1.7.2 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect ) koanf-providers-vault-v2.0.1/providers/vault/go.sum000066400000000000000000000211501454017643500224550ustar00rootroot00000000000000github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/providers/vault/vault.go000066400000000000000000000054101454017643500230050ustar00rootroot00000000000000// Package vault implements a koanf.Provider for Hashicorp Vault KV secrets engine // and provides it to koanf to be parsed by a koanf.Parser. package vault import ( "context" "errors" "net/http" "time" "github.com/hashicorp/vault/api" "github.com/knadh/koanf/maps" ) type Config struct { // Vault server address Address string // AuthMethod the Vault auth method https://developer.hashicorp.com/vault/docs/auth AuthMethod api.AuthMethod // Vault static token Token string // Secret data path Path string // If FlatPaths is true, then the loaded configuration is not split into // hierarchical maps based on the delimiter. The keys including the delimiter, // eg: app.db.name stays as-is in the confmap. FlatPaths bool // Delim is the delimiter to use // when specifying config key paths, for instance a . for `parent.child.key` // or a / for `parent/child/key`. Delim string // Internal HTTP client timeout Timeout time.Duration // Transport the optional HTTP client transport allows you to // customize the settings like InsecureSkipVerify Transport *http.Transport // ExcludeMeta states whether the secret should be returned with its metadata. // If ExcludeMeta is true, no metadata will be returned, and the data can be // accessed as `k.String("key")`. If set to false, the value for data `key` // and the metadata `version` can be accessed as `k.String("data.key")` and // `k.Int("metadata.version")`. ExcludeMeta bool } type Vault struct { client *api.Client cfg Config } // Provider returns a provider that takes a Vault config. func Provider(cfg Config) (*Vault, error) { httpClient := &http.Client{Timeout: cfg.Timeout, Transport: cfg.Transport} client, err := api.NewClient(&api.Config{Address: cfg.Address, HttpClient: httpClient}) if err != nil { return nil, err } if cfg.AuthMethod != nil { if _, err := client.Auth().Login(context.Background(), cfg.AuthMethod); err != nil { return nil, err } } else { client.SetToken(cfg.Token) } return &Vault{client: client, cfg: cfg}, nil } // ReadBytes is not supported by the vault provider. func (r *Vault) ReadBytes() ([]byte, error) { return nil, errors.New("vault provider does not support this method") } // Read fetches the configuration from the source and returns a nested config map. func (r *Vault) Read() (map[string]interface{}, error) { secret, err := r.client.Logical().Read(r.cfg.Path) if err != nil { return nil, err } if secret == nil { return nil, errors.New("vault provider fetched no data") } s := secret.Data if r.cfg.ExcludeMeta { s = secret.Data["data"].(map[string]interface{}) } // Unflatten only when a delimiter is specified if !r.cfg.FlatPaths && r.cfg.Delim != "" { data := maps.Unflatten(s, r.cfg.Delim) return data, nil } return s, nil } koanf-providers-vault-v2.0.1/tests/000077500000000000000000000000001454017643500173155ustar00rootroot00000000000000koanf-providers-vault-v2.0.1/tests/fs_test.go000066400000000000000000000117251454017643500213210ustar00rootroot00000000000000package koanf_test import ( "fmt" "os" "testing" "testing/fstest" "time" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/providers/fs" "github.com/knadh/koanf/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestFSProvider(t *testing.T) { var ( assert = assert.New(t) ) cases := []Case{ {koanf: koanf.New("."), file: "mock.json", parser: json.Parser(), typeName: "json"}, } // load file system testFS := os.DirFS("../mock") for _, c := range cases { // Test fs.FS before setting up kaonf err := fstest.TestFS(testFS, c.file) require.NoError(t, err, "failed asserting file existence in fs.FS") // koanf setup p := fs.Provider(testFS, c.file) err = c.koanf.Load(p, c.parser) require.NoError(t, err, fmt.Sprintf("error loading: %v", c.file)) // Type. require.Equal(t, c.typeName, c.koanf.Get("type")) assert.Equal(nil, c.koanf.Get("xxx")) assert.Equal(make(map[string]interface{}), c.koanf.Get("empty")) // Int. assert.Equal(int64(0), c.koanf.Int64("xxxx")) assert.Equal(int64(1234), c.koanf.Int64("parent1.id")) assert.Equal(int(0), c.koanf.Int("xxxx")) assert.Equal(int(1234), c.koanf.Int("parent1.id")) assert.Equal([]int64{}, c.koanf.Int64s("xxxx")) assert.Equal([]int64{1, 2, 3}, c.koanf.Int64s("parent1.child1.grandchild1.ids")) assert.Equal(map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Int64Map("parent1.intmap")) assert.Equal(map[string]int64{}, c.koanf.Int64Map("parent1.boolmap")) assert.Equal(map[string]int64{}, c.koanf.Int64Map("xxxx")) assert.Equal(map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Int64Map("parent1.floatmap")) assert.Equal([]int{1, 2, 3}, c.koanf.Ints("parent1.child1.grandchild1.ids")) assert.Equal([]int{}, c.koanf.Ints("xxxx")) assert.Equal(map[string]int{"key1": 1, "key2": 1, "key3": 1}, c.koanf.IntMap("parent1.intmap")) assert.Equal(map[string]int{}, c.koanf.IntMap("parent1.boolmap")) assert.Equal(map[string]int{}, c.koanf.IntMap("xxxx")) // Float. assert.Equal(float64(0), c.koanf.Float64("xxx")) assert.Equal(float64(1234), c.koanf.Float64("parent1.id")) assert.Equal([]float64{}, c.koanf.Float64s("xxxx")) assert.Equal([]float64{1, 2, 3}, c.koanf.Float64s("parent1.child1.grandchild1.ids")) assert.Equal(map[string]float64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Float64Map("parent1.intmap")) assert.Equal(map[string]float64{"key1": 1.1, "key2": 1.2, "key3": 1.3}, c.koanf.Float64Map("parent1.floatmap")) assert.Equal(map[string]float64{}, c.koanf.Float64Map("parent1.boolmap")) assert.Equal(map[string]float64{}, c.koanf.Float64Map("xxxx")) // String and bytes. assert.Equal([]byte{}, c.koanf.Bytes("xxxx")) assert.Equal([]byte("parent1"), c.koanf.Bytes("parent1.name")) assert.Equal("", c.koanf.String("xxxx")) assert.Equal("parent1", c.koanf.String("parent1.name")) assert.Equal([]string{}, c.koanf.Strings("xxxx")) assert.Equal([]string{"red", "blue", "orange"}, c.koanf.Strings("orphan")) assert.Equal(map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, c.koanf.StringMap("parent1.strmap")) assert.Equal(map[string][]string{"key1": {"val1", "val2", "val3"}, "key2": {"val4", "val5"}}, c.koanf.StringsMap("parent1.strsmap")) assert.Equal(map[string]string{}, c.koanf.StringMap("xxxx")) assert.Equal(map[string]string{}, c.koanf.StringMap("parent1.intmap")) // Bools. assert.Equal(false, c.koanf.Bool("xxxx")) assert.Equal(false, c.koanf.Bool("type")) assert.Equal(true, c.koanf.Bool("parent1.child1.grandchild1.on")) assert.Equal(true, c.koanf.Bool("strbool")) assert.Equal([]bool{}, c.koanf.Bools("xxxx")) assert.Equal([]bool{true, false, true}, c.koanf.Bools("bools")) assert.Equal([]bool{true, false, true}, c.koanf.Bools("intbools")) assert.Equal([]bool{true, true, false}, c.koanf.Bools("strbools")) assert.Equal(map[string]bool{"ok1": true, "ok2": true, "notok3": false}, c.koanf.BoolMap("parent1.boolmap")) assert.Equal(map[string]bool{"key1": true, "key2": true, "key3": true}, c.koanf.BoolMap("parent1.intmap")) assert.Equal(map[string]bool{}, c.koanf.BoolMap("xxxx")) // Others. assert.Equal(time.Duration(1234), c.koanf.Duration("parent1.id")) assert.Equal(time.Duration(0), c.koanf.Duration("xxxx")) assert.Equal(time.Second*3, c.koanf.Duration("duration")) assert.Equal(time.Time{}, c.koanf.Time("xxxx", "2006-01-02")) assert.Equal(time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), c.koanf.Time("time", "2006-01-02")) assert.Equal([]string{}, c.koanf.MapKeys("xxxx"), "map keys mismatch") assert.Equal([]string{"bools", "duration", "empty", "intbools", "negative_int", "orphan", "parent1", "parent2", "strbool", "strbools", "time", "type"}, c.koanf.MapKeys(""), "map keys mismatch") assert.Equal([]string{"key1", "key2", "key3"}, c.koanf.MapKeys("parent1.strmap"), "map keys mismatch") // Attempt to parse int=1234 as a Unix timestamp. assert.Equal(time.Date(1970, 1, 1, 0, 20, 34, 0, time.UTC), c.koanf.Time("parent1.id", "").UTC()) } } koanf-providers-vault-v2.0.1/tests/go.mod000066400000000000000000000054271454017643500204330ustar00rootroot00000000000000module koanf_test go 1.18 replace ( github.com/knadh/koanf/maps => ../maps github.com/knadh/koanf/parsers/dotenv => ../parsers/dotenv github.com/knadh/koanf/parsers/hcl => ../parsers/hcl github.com/knadh/koanf/parsers/hjson => ../parsers/hjson github.com/knadh/koanf/parsers/json => ../parsers/json github.com/knadh/koanf/parsers/toml => ../parsers/toml github.com/knadh/koanf/parsers/yaml => ../parsers/yaml github.com/knadh/koanf/providers/basicflag => ../providers/basicflag github.com/knadh/koanf/providers/confmap => ../providers/confmap github.com/knadh/koanf/providers/env => ../providers/env github.com/knadh/koanf/providers/file => ../providers/file github.com/knadh/koanf/providers/fs => ../providers/fs github.com/knadh/koanf/providers/posflag => ../providers/posflag github.com/knadh/koanf/providers/rawbytes => ../providers/rawbytes github.com/knadh/koanf/providers/structs => ../providers/structs github.com/knadh/koanf/v2 => ../ ) require ( github.com/knadh/koanf/maps v0.1.1 github.com/knadh/koanf/parsers/dotenv v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/parsers/hcl v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/parsers/hjson v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/parsers/json v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/parsers/toml v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/parsers/yaml v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/basicflag v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/confmap v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/env v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/file v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/fs v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/posflag v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/rawbytes v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/providers/structs v0.0.0-00010101000000-000000000000 github.com/knadh/koanf/v2 v2.0.0-00010101000000-000000000000 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hjson/hjson-go/v4 v4.3.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) koanf-providers-vault-v2.0.1/tests/go.sum000066400000000000000000000066151454017643500204600ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hjson/hjson-go/v4 v4.3.0 h1:dyrzJdqqFGhHt+FSrs5n9s6b0fPM8oSJdWo+oS3YnJw= github.com/hjson/hjson-go/v4 v4.3.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= koanf-providers-vault-v2.0.1/tests/koanf_test.go000066400000000000000000001262611454017643500220110ustar00rootroot00000000000000package koanf_test import ( encjson "encoding/json" "errors" "flag" "fmt" "log" "os" "path/filepath" "regexp" "strconv" "strings" "sync" "testing" "time" "github.com/knadh/koanf/parsers/dotenv" "github.com/knadh/koanf/parsers/hcl" "github.com/knadh/koanf/parsers/hjson" "github.com/knadh/koanf/parsers/json" "github.com/knadh/koanf/parsers/toml" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/basicflag" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/posflag" "github.com/knadh/koanf/providers/rawbytes" "github.com/knadh/koanf/v2" "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const ( delim = "." mockDir = "../mock" mockJSON = mockDir + "/mock.json" mockYAML = mockDir + "/mock.yml" mockTOML = mockDir + "/mock.toml" mockHCL = mockDir + "/mock.hcl" mockProp = mockDir + "/mock.prop" mockDotEnv = mockDir + "/mock.env" mockHJSON = mockDir + "/mock.hjson" ) // Ordered list of fields in the 'flat' test confs. var flatTestKeys = []string{ "COMMENT", "MORE", "MiXeD", "UPPER", "empty", "lower", "quotedSpecial", } var flatTestKeyMap = map[string][]string{ "COMMENT": {"COMMENT"}, "MORE": {"MORE"}, "MiXeD": {"MiXeD"}, "UPPER": {"UPPER"}, "empty": {"empty"}, "lower": {"lower"}, "quotedSpecial": {"quotedSpecial"}, } var flatTestAll = `COMMENT -> AFTER MORE -> vars MiXeD -> CaSe UPPER -> CASE empty -> lower -> case quotedSpecial -> j18120734xn2&*@#*&R#d1j23d*(*)` // Ordered list of fields in the test confs. var testKeys = []string{ "bools", "duration", "empty", "intbools", "negative_int", "orphan", "parent1.boolmap.notok3", "parent1.boolmap.ok1", "parent1.boolmap.ok2", "parent1.child1.empty", "parent1.child1.grandchild1.ids", "parent1.child1.grandchild1.on", "parent1.child1.name", "parent1.child1.type", "parent1.floatmap.key1", "parent1.floatmap.key2", "parent1.floatmap.key3", "parent1.id", "parent1.intmap.key1", "parent1.intmap.key2", "parent1.intmap.key3", "parent1.name", "parent1.strmap.key1", "parent1.strmap.key2", "parent1.strmap.key3", "parent1.strsmap.key1", "parent1.strsmap.key2", "parent2.child2.empty", "parent2.child2.grandchild2.ids", "parent2.child2.grandchild2.on", "parent2.child2.name", "parent2.id", "parent2.name", "strbool", "strbools", "time", "type", } var testKeyMap = map[string][]string{ "bools": {"bools"}, "duration": {"duration"}, "empty": {"empty"}, "intbools": {"intbools"}, "negative_int": {"negative_int"}, "orphan": {"orphan"}, "parent1": {"parent1"}, "parent1.boolmap": {"parent1", "boolmap"}, "parent1.boolmap.notok3": {"parent1", "boolmap", "notok3"}, "parent1.boolmap.ok1": {"parent1", "boolmap", "ok1"}, "parent1.boolmap.ok2": {"parent1", "boolmap", "ok2"}, "parent1.child1": {"parent1", "child1"}, "parent1.child1.empty": {"parent1", "child1", "empty"}, "parent1.child1.grandchild1": {"parent1", "child1", "grandchild1"}, "parent1.child1.grandchild1.ids": {"parent1", "child1", "grandchild1", "ids"}, "parent1.child1.grandchild1.on": {"parent1", "child1", "grandchild1", "on"}, "parent1.child1.name": {"parent1", "child1", "name"}, "parent1.child1.type": {"parent1", "child1", "type"}, "parent1.floatmap": {"parent1", "floatmap"}, "parent1.floatmap.key1": {"parent1", "floatmap", "key1"}, "parent1.floatmap.key2": {"parent1", "floatmap", "key2"}, "parent1.floatmap.key3": {"parent1", "floatmap", "key3"}, "parent1.id": {"parent1", "id"}, "parent1.intmap": {"parent1", "intmap"}, "parent1.intmap.key1": {"parent1", "intmap", "key1"}, "parent1.intmap.key2": {"parent1", "intmap", "key2"}, "parent1.intmap.key3": {"parent1", "intmap", "key3"}, "parent1.name": {"parent1", "name"}, "parent1.strmap": {"parent1", "strmap"}, "parent1.strmap.key1": {"parent1", "strmap", "key1"}, "parent1.strmap.key2": {"parent1", "strmap", "key2"}, "parent1.strmap.key3": {"parent1", "strmap", "key3"}, "parent1.strsmap": {"parent1", "strsmap"}, "parent1.strsmap.key1": {"parent1", "strsmap", "key1"}, "parent1.strsmap.key2": {"parent1", "strsmap", "key2"}, "parent2": {"parent2"}, "parent2.child2": {"parent2", "child2"}, "parent2.child2.empty": {"parent2", "child2", "empty"}, "parent2.child2.grandchild2": {"parent2", "child2", "grandchild2"}, "parent2.child2.grandchild2.ids": {"parent2", "child2", "grandchild2", "ids"}, "parent2.child2.grandchild2.on": {"parent2", "child2", "grandchild2", "on"}, "parent2.child2.name": {"parent2", "child2", "name"}, "parent2.id": {"parent2", "id"}, "parent2.name": {"parent2", "name"}, "strbool": {"strbool"}, "strbools": {"strbools"}, "time": {"time"}, "type": {"type"}, } // `parent1.child1.type` and `type` are excluded as their // values vary between files. var testAll = `bools -> [true false true] duration -> 3s empty -> map[] intbools -> [1 0 1] negative_int -> -1234 orphan -> [red blue orange] parent1.boolmap.notok3 -> false parent1.boolmap.ok1 -> true parent1.boolmap.ok2 -> true parent1.child1.empty -> map[] parent1.child1.grandchild1.ids -> [1 2 3] parent1.child1.grandchild1.on -> true parent1.child1.name -> child1 parent1.floatmap.key1 -> 1.1 parent1.floatmap.key2 -> 1.2 parent1.floatmap.key3 -> 1.3 parent1.id -> 1234 parent1.intmap.key1 -> 1 parent1.intmap.key2 -> 1 parent1.intmap.key3 -> 1 parent1.name -> parent1 parent1.strmap.key1 -> val1 parent1.strmap.key2 -> val2 parent1.strmap.key3 -> val3 parent1.strsmap.key1 -> [val1 val2 val3] parent1.strsmap.key2 -> [val4 val5] parent2.child2.empty -> map[] parent2.child2.grandchild2.ids -> [4 5 6] parent2.child2.grandchild2.on -> true parent2.child2.name -> child2 parent2.id -> 5678 parent2.name -> parent2 strbool -> 1 strbools -> [1 t f] time -> 2019-01-01` var testParent2 = `child2.empty -> map[] child2.grandchild2.ids -> [4 5 6] child2.grandchild2.on -> true child2.name -> child2 id -> 5678 name -> parent2` type parentStruct struct { Name string `koanf:"name"` ID int `koanf:"id"` Child1 childStruct `koanf:"child1"` } type childStruct struct { Name string `koanf:"name"` Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Grandchild1 grandchildStruct `koanf:"grandchild1"` } type grandchildStruct struct { Ids []int `koanf:"ids"` On bool `koanf:"on"` } type testStruct struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1 parentStruct `koanf:"parent1"` } type testStructFlat struct { Type string `koanf:"type"` Empty map[string]string `koanf:"empty"` Parent1Name string `koanf:"parent1.name"` Parent1ID int `koanf:"parent1.id"` Parent1Child1Name string `koanf:"parent1.child1.name"` Parent1Child1Type string `koanf:"parent1.child1.type"` Parent1Child1Empty map[string]string `koanf:"parent1.child1.empty"` Parent1Child1Grandchild1IDs []int `koanf:"parent1.child1.grandchild1.ids"` Parent1Child1Grandchild1On bool `koanf:"parent1.child1.grandchild1.on"` } type customText int func (c *customText) UnmarshalText(text []byte) error { s := strings.ToLower(string(text)) switch { case strings.HasSuffix(s, "mb"): s = strings.TrimSuffix(s, "mb") default: s = "0" } v, err := strconv.ParseFloat(s, 64) if err != nil { return err } *c = customText(v) return nil } type Case struct { koanf *koanf.Koanf file string parser koanf.Parser typeName string } // 'Flat' Case instances to be used in multiple tests. These will not be // mutated. var flatCases = []Case{ {koanf: koanf.New(delim), file: mockDotEnv, parser: dotenv.Parser(), typeName: "dotenv"}, } // Case instances to be used in multiple tests. These will not be mutated. var cases = []Case{ {koanf: koanf.New(delim), file: mockJSON, parser: json.Parser(), typeName: "json"}, {koanf: koanf.New(delim), file: mockYAML, parser: yaml.Parser(), typeName: "yml"}, {koanf: koanf.New(delim), file: mockTOML, parser: toml.Parser(), typeName: "toml"}, {koanf: koanf.New(delim), file: mockHCL, parser: hcl.Parser(true), typeName: "hcl"}, {koanf: koanf.New(delim), file: mockHJSON, parser: hjson.Parser(), typeName: "hjson"}, } func init() { // Preload 4 Koanf instances with their providers and config. if err := cases[0].koanf.Load(file.Provider(cases[0].file), json.Parser()); err != nil { log.Fatalf("error loading config file: %v", err) } if err := cases[1].koanf.Load(file.Provider(cases[1].file), yaml.Parser()); err != nil { log.Fatalf("error loading config file: %v", err) } if err := cases[2].koanf.Load(file.Provider(cases[2].file), toml.Parser()); err != nil { log.Fatalf("error loading config file: %v", err) } if err := cases[3].koanf.Load(file.Provider(cases[3].file), hcl.Parser(true)); err != nil { log.Fatalf("error loading config file: %v", err) } if err := cases[4].koanf.Load(file.Provider(cases[4].file), hjson.Parser()); err != nil { log.Fatalf("error loading config file: %v", err) } // Preload 1 'flat' Koanf instances with their providers and config. if err := flatCases[0].koanf.Load(file.Provider(flatCases[0].file), dotenv.Parser()); err != nil { log.Fatalf("error loading config file: %v", err) } } func BenchmarkLoadFile(b *testing.B) { k := koanf.New(delim) // Don't use TOML here because it distorts memory benchmarks due to high memory use providers := []*file.File{file.Provider(mockJSON), file.Provider(mockYAML)} parsers := []koanf.Parser{json.Parser(), yaml.Parser()} b.ResetTimer() for n := 0; n < b.N; n++ { if err := k.Load(providers[n%2], parsers[n%2]); err != nil { b.Fatalf("Unexpected error: %+v", k) } } } func TestLoadFile(t *testing.T) { // Load a non-existent file. _, err := file.Provider("does-not-exist").ReadBytes() assert.NotNil(t, err, "no error for non-existent file") // Load a valid file. _, err = file.Provider(mockJSON).ReadBytes() assert.Nil(t, err, "error loading file") } func TestLoadFlatFileAllKeys(t *testing.T) { assert := assert.New(t) re, _ := regexp.Compile("(.+?)?type \\-> (.*)\n") for _, c := range flatCases { // Check against testKeys. assert.Equal(flatTestKeys, c.koanf.Keys(), fmt.Sprintf("loaded keys mismatch: %v", c.typeName)) // Check against keyMap. assert.EqualValues(flatTestKeyMap, c.koanf.KeyMap(), "keymap doesn't match") // Replace the "type" fields that varies across different files // to do a complete key -> value map match with testAll. s := strings.TrimSpace(re.ReplaceAllString(c.koanf.Sprint(), "")) assert.Equal(flatTestAll, s, fmt.Sprintf("key -> value list mismatch: %v", c.typeName)) } } func TestLoadFileAllKeys(t *testing.T) { assert := assert.New(t) re, _ := regexp.Compile("(.+?)?type \\-> (.*)\n") for _, c := range cases { // Check against testKeys. assert.Equal(testKeys, c.koanf.Keys(), fmt.Sprintf("loaded keys mismatch: %v", c.typeName)) // Check against keyMap. assert.EqualValues(testKeyMap, c.koanf.KeyMap(), "keymap doesn't match") // Replace the "type" fields that varies across different files // to do a complete key -> value map match with testAll. s := strings.TrimSpace(re.ReplaceAllString(c.koanf.Sprint(), "")) assert.Equal(testAll, s, fmt.Sprintf("key -> value list mismatch: %v", c.typeName)) } } func TestDelim(t *testing.T) { k1 := koanf.New(".") assert.Equal(t, k1.Delim(), ".") k2 := koanf.New("/") assert.Equal(t, k2.Delim(), "/") } func TestLoadMergeYamlJson(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.NoError(k.Load(file.Provider(mockYAML), yaml.Parser()), "error loading file") // loading json after yaml causes the intbools to be loaded as []float64 assert.NoError(k.Load(file.Provider(mockJSON), yaml.Parser()), "error loading file") // checking that there is no issues with expecting it to be an []int64 v := k.Int64s("intbools") assert.Len(v, 3) defer func() { if err := recover(); err != nil { assert.Failf("panic", "received panic: %v", err) } }() v2 := k.MustInt64s("intbools") assert.Len(v2, 3) } func TestLoadMergeJsonYaml(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.NoError(k.Load(file.Provider(mockJSON), yaml.Parser()), "error loading file") // loading yaml after json causes the intbools to be loaded as []int after json loaded it with []float64 assert.NoError(k.Load(file.Provider(mockYAML), yaml.Parser()), "error loading file") // checking that there is no issues with expecting it to be an []float64 v := k.Float64s("intbools") assert.Len(v, 3) defer func() { if err := recover(); err != nil { assert.Failf("panic", "received panic: %v", err) } }() v2 := k.MustFloat64s("intbools") assert.Len(v2, 3) } func TestWatchFile(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) // Create a tmp config file. tmpDir, _ := os.MkdirTemp("", "koanf_*") // TODO: replace with t.TempDir() as of go v1.15 tmpFile := filepath.Join(tmpDir, "koanf_mock") err := os.WriteFile(tmpFile, []byte(`{"parent": {"name": "name1"}}`), 0600) require.NoError(t, err, "error creating temp config file: %v", err) // Load the new config and watch it for changes. f := file.Provider(tmpFile) k.Load(f, json.Parser()) // Watch for changes. changedC := make(chan string, 1) var wg sync.WaitGroup wg.Add(1) // our assurance that cb is called max once f.Watch(func(event interface{}, err error) { // The File watcher always returns a nil `event`, which can // be ignored. if err != nil { // TODO: replace make with of Error Wrapping-Scheme and assert.ErrorIs() checks as of go v1.13 assert.Condition(func() bool { return strings.Contains(err.Error(), "was removed") }, "received unexpected error. err: %s", err) return } // Reload the config. k.Load(f, json.Parser()) changedC <- k.String("parent.name") wg.Done() }) // Wait a second and change the file. time.Sleep(1 * time.Second) os.WriteFile(tmpFile, []byte(`{"parent": {"name": "name2"}}`), 0600) wg.Wait() assert.Condition(func() bool { return strings.Compare(<-changedC, "name2") == 0 }, "file watch reload didn't change config") } func TestWatchFileSymlink(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) tmpDir, _ := os.MkdirTemp("", "koanf_*") // TODO: replace with t.TempDir() as of go v1.15 // Create a symlink. symPath := filepath.Join(tmpDir, "koanf_test_symlink") symPath2 := filepath.Join(tmpDir, "koanf_test_symlink2") wd, err := os.Getwd() assert.NoError(err, "error getting working dir") jsonFile := filepath.Join(wd, mockJSON) yamlFile := filepath.Join(wd, mockYAML) // Create a symlink to the JSON file which will be swapped out later. assert.NoError(os.Symlink(jsonFile, symPath), "error creating symlink") assert.NoError(os.Symlink(yamlFile, symPath2), "error creating symlink2") // Load the symlink (to the JSON) file. f := file.Provider(symPath) k.Load(f, json.Parser()) // Watch for changes. changedC := make(chan string, 1) var wg sync.WaitGroup wg.Add(1) // our assurance that cb is called max once f.Watch(func(event interface{}, err error) { // The File watcher always returns a nil `event`, which can // be ignored. if err != nil { // TODO: make use of Error Wrapping-Scheme and assert.ErrorIs() checks as of go v1.13 assert.Condition(func() bool { return strings.Contains(err.Error(), "no such file or directory") }, "received unexpected error. err: %s", err) return } // Reload the config. k.Load(f, yaml.Parser()) changedC <- k.String("type") wg.Done() }) // Wait a second and swap the symlink target from the JSON file to the YAML file. // Create a temp symlink to the YAML file and rename the old symlink to the new // symlink. We do this to avoid removing the symlink and triggering a REMOVE event. time.Sleep(1 * time.Second) assert.NoError(os.Rename(symPath2, symPath), "error swaping symlink to another file type") wg.Wait() assert.Condition(func() bool { return strings.Compare(<-changedC, "yml") == 0 }, "symlink watch reload didn't change config") } func TestLoadMerge(t *testing.T) { var ( assert = assert.New(t) // Load several types into a fresh Koanf instance. k = koanf.New(delim) ) for _, c := range cases { assert.Nil(k.Load(file.Provider(c.file), c.parser), fmt.Sprintf("error loading: %v", c.file)) // Check against testKeys. assert.Equal(testKeys, k.Keys(), fmt.Sprintf("loaded keys don't match in: %v", c.file)) // The 'type' fields in different file types have different values. // As each subsequent file is loaded, the previous value should be overridden. assert.Equal(c.typeName, k.String("type"), "types don't match") assert.Equal(c.typeName, k.String("parent1.child1.type"), "types don't match") } // Load env provider and override value. os.Setenv("PREFIX_PARENT1.CHILD1.TYPE", "env") err := k.Load(env.Provider("PREFIX_", ".", func(k string) string { return strings.Replace(strings.ToLower(k), "prefix_", "", -1) }), nil) assert.Nil(err, "error loading env") assert.Equal("env", k.String("parent1.child1.type"), "types don't match") // Test the env provider than can mutate the value to upper case err = k.Load(env.ProviderWithValue("PREFIX_", ".", func(k string, v string) (string, interface{}) { return strings.Replace(strings.ToLower(k), "prefix_", "", -1), strings.ToUpper(v) }), nil) assert.Nil(err, "error loading env with value") assert.Equal("ENV", k.String("parent1.child1.type"), "types don't match") // Override with the confmap provider. k.Load(confmap.Provider(map[string]interface{}{ "parent1.child1.type": "confmap", "type": "confmap", }, "."), nil) assert.Equal("confmap", k.String("parent1.child1.type"), "types don't match") assert.Equal("confmap", k.String("type"), "types don't match") // Override with the rawbytes provider. assert.Nil(k.Load(rawbytes.Provider([]byte(`{"type": "rawbytes", "parent1": {"child1": {"type": "rawbytes"}}}`)), json.Parser()), "error loading raw bytes") assert.Equal("rawbytes", k.String("parent1.child1.type"), "types don't match") assert.Equal("rawbytes", k.String("type"), "types don't match") } func TestFlags(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockJSON), json.Parser()), "error loading file") k2 := k.Copy() k3 := k.Copy() // Override with the posflag provider. f := pflag.NewFlagSet("test", pflag.ContinueOnError) // Key that exists in the loaded conf. Should overwrite with Set(). f.String("parent1.child1.type", "flag", "") f.Set("parent1.child1.type", "flag") f.StringSlice("stringslice", []string{"a", "b", "c"}, "") f.IntSlice("intslice", []int{1, 2, 3}, "") // Key that doesn't exist in the loaded file conf. Should merge the default value. f.String("flagkey", "flag", "") // Key that exists in the loadd conf but no Set(). Default value shouldn't be merged. f.String("parent1.name", "flag", "") // Initialize the provider with the Koanf instance passed where default values // will merge if the keys are not present in the conf map. assert.Nil(k.Load(posflag.Provider(f, ".", k), nil), "error loading posflag") assert.Equal("flag", k.String("parent1.child1.type"), "types don't match") assert.Equal("flag", k.String("flagkey"), "value doesn't match") assert.NotEqual("flag", k.String("parent1.name"), "value doesn't match") assert.Equal([]string{"a", "b", "c"}, k.Strings("stringslice"), "value doesn't match") assert.Equal([]int{1, 2, 3}, k.Ints("intslice"), "value doesn't match") // Test the posflag provider can mutate the value to upper case assert.Nil(k3.Load(posflag.ProviderWithValue(f, ".", nil, func(k string, v string) (string, interface{}) { return strings.Replace(strings.ToLower(k), "prefix_", "", -1), strings.ToUpper(v) }), nil), "error loading posflag") assert.Equal("FLAG", k3.String("parent1.child1.type"), "types don't match") // Test without passing the Koanf instance where default values will not merge. assert.Nil(k2.Load(posflag.Provider(f, ".", nil), nil), "error loading posflag") assert.Equal("flag", k2.String("parent1.child1.type"), "types don't match") assert.Equal("", k2.String("flagkey"), "value doesn't match") assert.NotEqual("", k2.String("parent1.name"), "value doesn't match") // Override with the flag provider. bf := flag.NewFlagSet("test", flag.ContinueOnError) bf.String("parent1.child1.type", "flag", "") bf.Set("parent1.child1.type", "basicflag") assert.Nil(k.Load(basicflag.Provider(bf, "."), nil), "error loading basicflag") assert.Equal("basicflag", k.String("parent1.child1.type"), "types don't match") // Test the basicflag provider can mutate the value to upper case bf2 := flag.NewFlagSet("test", flag.ContinueOnError) bf2.String("parent1.child1.type", "flag", "") bf2.Set("parent1.child1.type", "basicflag") assert.Nil(k.Load(basicflag.ProviderWithValue(bf2, ".", func(k string, v string) (string, interface{}) { return strings.Replace(strings.ToLower(k), "prefix_", "", -1), strings.ToUpper(v) }), nil), "error loading basicflag") assert.Equal("BASICFLAG", k.String("parent1.child1.type"), "types don't match") } func TestConfMapValues(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockJSON), json.Parser()), "error loading file") var ( c1 = k.All() ra1 = k.Raw() r1 = k.Cut("parent2").Raw() ) k = koanf.New(delim) assert.Nil(k.Load(file.Provider(mockJSON), json.Parser()), "error loading file") var ( c2 = k.All() ra2 = k.Raw() r2 = k.Cut("parent2").Raw() ) assert.EqualValues(c1, c2, "conf map mismatch") assert.EqualValues(ra1, ra2, "conf map mismatch") assert.EqualValues(r1, r2, "conf map mismatch") } func TestCutCopy(t *testing.T) { // Instance 1. var ( assert = assert.New(t) k1 = koanf.New(delim) ) assert.Nil(k1.Load(file.Provider(mockJSON), json.Parser()), "error loading file") var ( cp1 = k1.Copy() cut1 = k1.Cut("") cutp1 = k1.Cut("parent2") ) // Instance 2. k2 := koanf.New(delim) assert.Nil(k2.Load(file.Provider(mockJSON), json.Parser()), "error loading file") var ( cp2 = k2.Copy() cut2 = k2.Cut("") cutp2 = k2.Cut("parent2") ) assert.EqualValues(cp1.All(), cp2.All(), "conf map mismatch") assert.EqualValues(cut1.All(), cut2.All(), "conf map mismatch") assert.EqualValues(cutp1.All(), cutp2.All(), "conf map mismatch") assert.Equal(testParent2, strings.TrimSpace(cutp1.Sprint()), "conf map mismatch") assert.Equal(strings.TrimSpace(cutp1.Sprint()), strings.TrimSpace(cutp2.Sprint()), "conf map mismatch") // Cut a single field with no children. Should return empty conf maps. assert.Equal(k1.Cut("type").Keys(), k2.Cut("type").Keys(), "single field cut mismatch") assert.Equal(k1.Cut("xxxx").Keys(), k2.Cut("xxxx").Keys(), "single field cut mismatch") assert.Equal(len(k1.Cut("type").Raw()), 0, "non-map cut returned items") } func TestWithMergeFunc(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.NoError(k.Load(rawbytes.Provider([]byte(`{"foo":"bar"}`)), json.Parser())) assert.NoError(k.Load(rawbytes.Provider([]byte(`{"baz":"bar"}`)), json.Parser(), koanf.WithMergeFunc(func(a, b map[string]interface{}) error { // No merge return nil }))) assert.Equal(map[string]interface{}{ "foo": "bar", }, k.All(), "expects the result of the first load only") err := errors.New("stub") assert.ErrorIs(k.Load(rawbytes.Provider([]byte(`{"baz":"bar"}`)), json.Parser(), koanf.WithMergeFunc(func(a, b map[string]interface{}) error { return err })), err, "expects the error thrown by WithMergeFunc") } func TestMerge(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockJSON), json.Parser()), "error loading file") // Make two different cuts that'll have different confmaps. var ( cut1 = k.Cut("parent1") cut2 = k.Cut("parent2") ) assert.NotEqual(cut1.All(), cut2.All(), "different cuts incorrectly match") assert.NotEqual(cut1.Sprint(), cut2.Sprint(), "different cuts incorrectly match") // Create an empty Koanf instance. k2 := koanf.New(delim) // Merge cut1 into it and check if they match. k2.Merge(cut1) assert.Equal(cut1.All(), k2.All(), "conf map mismatch") } func TestRaw_YamlTypes(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockYAML), yaml.Parser()), "error loading file") raw := k.Raw() i, ok := raw["intbools"] assert.True(ok, "ints key does not exist in the map") arr, ok := i.([]interface{}) assert.True(ok, "arr slice is not array of integers") for _, integer := range arr { if _, ok := integer.(int); !ok { assert.Failf("failure", "%v not an integer but %T", integer, integer) } } } func TestRaw_JsonTypes(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockJSON), json.Parser()), "error loading file") raw := k.Raw() i, ok := raw["intbools"] assert.True(ok, "ints key does not exist in the map") arr, ok := i.([]interface{}) assert.True(ok, "arr slice is not array of integers") for _, integer := range arr { if _, ok := integer.(float64); !ok { assert.Failf("failure", "%v not an integer but %T", integer, integer) } } } func TestMergeStrictError(t *testing.T) { var ( assert = assert.New(t) ) ks := koanf.NewWithConf(koanf.Conf{ Delim: delim, StrictMerge: true, }) assert.Nil(ks.Load(confmap.Provider(map[string]interface{}{ "parent2": map[string]interface{}{ "child2": map[string]interface{}{ "grandchild2": map[string]interface{}{ "ids": 123, }, }, }, }, delim), nil)) err := ks.Load(file.Provider(mockYAML), yaml.Parser()) assert.Error(err) assert.True(strings.HasPrefix(err.Error(), "incorrect types at key parent2.child2.grandchild2")) } func TestMergeAt(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockYAML), yaml.Parser()), "error loading file") // Get expected koanf, and root data var ( expected = k.Cut("parent2") rootData = map[string]interface{}{ "name": k.String("parent2.name"), "id": k.Int("parent2.id"), } ) // Get nested test data to merge at path child2 := koanf.New(delim) assert.Nil(child2.Load(confmap.Provider(map[string]interface{}{ "name": k.String("parent2.child2.name"), "empty": k.Get("parent2.child2.empty"), }, delim), nil)) grandChild := k.Cut("parent2.child2.grandchild2") // Create test koanf ordered := koanf.New(delim) assert.Nil(ordered.Load(confmap.Provider(rootData, delim), nil)) // Merge at path in order, first child2, then child2.grandchild2 ordered.MergeAt(child2, "child2") ordered.MergeAt(grandChild, "child2.grandchild2") assert.Equal(expected.Get(""), ordered.Get(""), "conf map mismatch") // Create test koanf reversed := koanf.New(delim) assert.Nil(reversed.Load(confmap.Provider(rootData, delim), nil)) // Merge at path in reverse order, first child2.grandchild2, then child2 reversed.MergeAt(grandChild, "child2.grandchild2") reversed.MergeAt(child2, "child2") assert.Equal(expected.Get(""), reversed.Get(""), "conf map mismatch") } func TestSet(t *testing.T) { var ( assert = assert.New(t) k = koanf.New(delim) ) assert.Nil(k.Load(file.Provider(mockYAML), yaml.Parser()), "error loading file") assert.Nil(k.Set("parent1.name", "new")) assert.Equal(k.String("parent1.name"), "new") assert.Nil(k.Set("parent1.child1.name", 123)) assert.Equal(k.Int("parent1.child1.name"), 123) assert.Nil(k.Set("parent1.child1.grandchild1.ids", []int{5})) assert.Equal(k.Ints("parent1.child1.grandchild1.ids"), []int{5}) assert.Nil(k.Set("parent1.child1.grandchild1", 123)) assert.Equal(k.Int("parent1.child1.grandchild1"), 123) assert.Equal(k.Int("parent1.child1.grandchild1.ids"), 0) assert.Nil(k.Set("parent1.child1.grandchild1", map[string]interface{}{"name": "new"})) assert.Equal(k.Get("parent1.child1.grandchild1"), map[string]interface{}{"name": "new"}) } func TestUnmarshal(t *testing.T) { assert := assert.New(t) // Expected unmarshalled structure. real := testStruct{ Type: "json", Empty: make(map[string]string), Parent1: parentStruct{ Name: "parent1", ID: 1234, Child1: childStruct{ Name: "child1", Type: "json", Empty: make(map[string]string), Grandchild1: grandchildStruct{ Ids: []int{1, 2, 3}, On: true, }, }, }, } // Unmarshal and check all parsers. for _, c := range cases { var ( k = koanf.New(delim) ts testStruct ) assert.Nil(k.Load(file.Provider(c.file), c.parser), fmt.Sprintf("error loading: %v", c.file)) assert.Nil(k.Unmarshal("", &ts), "unmarshal failed") real.Type = c.typeName real.Parent1.Child1.Type = c.typeName assert.Equal(real, ts, "unmarshalled structs don't match") // Unmarshal with config. ts = testStruct{} assert.Nil(k.UnmarshalWithConf("", &ts, koanf.UnmarshalConf{Tag: "koanf"}), "unmarshal failed") real.Type = c.typeName real.Parent1.Child1.Type = c.typeName assert.Equal(real, ts, "unmarshalled structs don't match") } } func TestUnmarshalFlat(t *testing.T) { assert := assert.New(t) // Expected unmarshalled structure. real := testStructFlat{ Type: "json", Empty: make(map[string]string), Parent1Name: "parent1", Parent1ID: 1234, Parent1Child1Name: "child1", Parent1Child1Type: "json", Parent1Child1Empty: make(map[string]string), Parent1Child1Grandchild1IDs: []int{1, 2, 3}, Parent1Child1Grandchild1On: true, } // Unmarshal and check all parsers. for _, c := range cases { k := koanf.New(delim) assert.Nil(k.Load(file.Provider(c.file), c.parser), fmt.Sprintf("error loading: %v", c.file)) ts := testStructFlat{} assert.Nil(k.UnmarshalWithConf("", &ts, koanf.UnmarshalConf{Tag: "koanf", FlatPaths: true}), "unmarshal failed") real.Type = c.typeName real.Parent1Child1Type = c.typeName assert.Equal(real, ts, "unmarshalled structs don't match") } } func TestUnmarshalCustomText(t *testing.T) { test := struct { V1 customText `koanf:"v1"` V2 string `koanf:"v2"` V3 customText `koanf:"v3"` }{} // Test custom unmarshalling of strings via mapstructure's UnmarshalText() // methods. customText is a int type that strips of the `mb` suffix and parses // the rest into a number. k := koanf.New(delim) err := k.Load(rawbytes.Provider([]byte(`{"v1": "42mb", "v2": "42mb"}`)), json.Parser()) assert.NoError(t, err) k.Unmarshal("", &test) assert.Equal(t, int(test.V1), 42) assert.Equal(t, test.V2, "42mb") assert.Equal(t, int(test.V3), 0) } func TestMarshal(t *testing.T) { assert := assert.New(t) for _, c := range cases { // HCL does not support marshalling. if c.typeName == "hcl" { continue } // Load config. k := koanf.New(delim) assert.NoError(k.Load(file.Provider(c.file), c.parser), fmt.Sprintf("error loading: %v", c.file)) // Serialize / marshal into raw bytes using the parser. b, err := k.Marshal(c.parser) assert.NoError(err, "error marshalling") // Reload raw serialize bytes into a new koanf instance. k = koanf.New(delim) assert.NoError(k.Load(rawbytes.Provider(b), c.parser), fmt.Sprintf("error loading: %v", c.file)) // Check if values are intact. assert.Equal(float64(1234), c.koanf.MustFloat64("parent1.id")) assert.Equal([]string{"red", "blue", "orange"}, c.koanf.MustStrings("orphan")) assert.Equal([]int64{1, 2, 3}, c.koanf.MustInt64s("parent1.child1.grandchild1.ids")) } } func TestGetExists(t *testing.T) { assert := assert.New(t) type exCase struct { path string exists bool } exCases := []exCase{ {"xxxxx", false}, {"parent1.child2", false}, {"child1", false}, {"child2", false}, {"type", true}, {"parent1", true}, {"parent2", true}, {"parent1.name", true}, {"parent2.name", true}, {"parent1.child1", true}, {"parent2.child2", true}, {"parent1.child1.grandchild1", true}, {"parent1.child1.grandchild1.on", true}, {"parent2.child2.grandchild2.on", true}, } for _, c := range exCases { assert.Equal(c.exists, cases[0].koanf.Exists(c.path), fmt.Sprintf("path resolution failed: %s", c.path)) assert.Equal(c.exists, cases[0].koanf.Get(c.path) != nil, fmt.Sprintf("path resolution failed: %s", c.path)) } } func TestSlices(t *testing.T) { assert := assert.New(t) // Load a slice of confmaps [{}, {}]. var mp map[string]interface{} err := encjson.Unmarshal([]byte(`{ "parent": [ {"value": 1, "sub": {"value": "1"}}, {"value": 2, "sub": {"value": "2"}} ], "another": "123" }`), &mp) assert.NoError(err, "error marshalling test payload") k := koanf.New(delim) assert.NoError(k.Load(confmap.Provider(mp, "."), nil)) assert.Empty(k.Slices("x")) assert.Empty(k.Slices("parent.value")) assert.Empty(k.Slices("parent.value.sub")) slices := k.Slices("parent") assert.NotNil(slices, "got nil slice of confmap") assert.NotEmpty(slices, "got empty confmap slice") for i, s := range slices { assert.Equal(s.Int("value"), i+1) assert.Equal(s.String("sub.value"), fmt.Sprintf("%d", i+1)) } } func TestGetTypes(t *testing.T) { assert := assert.New(t) for _, c := range cases { assert.Equal(nil, c.koanf.Get("xxx")) assert.Equal(make(map[string]interface{}), c.koanf.Get("empty")) // Int. assert.Equal(int64(0), c.koanf.Int64("xxxx")) assert.Equal(int64(1234), c.koanf.Int64("parent1.id")) assert.Equal(int(0), c.koanf.Int("xxxx")) assert.Equal(int(1234), c.koanf.Int("parent1.id")) assert.Equal([]int64{}, c.koanf.Int64s("xxxx")) assert.Equal([]int64{1, 2, 3}, c.koanf.Int64s("parent1.child1.grandchild1.ids")) assert.Equal(map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Int64Map("parent1.intmap")) assert.Equal(map[string]int64{}, c.koanf.Int64Map("parent1.boolmap")) assert.Equal(map[string]int64{}, c.koanf.Int64Map("xxxx")) assert.Equal(map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Int64Map("parent1.floatmap")) assert.Equal([]int{1, 2, 3}, c.koanf.Ints("parent1.child1.grandchild1.ids")) assert.Equal([]int{}, c.koanf.Ints("xxxx")) assert.Equal(map[string]int{"key1": 1, "key2": 1, "key3": 1}, c.koanf.IntMap("parent1.intmap")) assert.Equal(map[string]int{}, c.koanf.IntMap("parent1.boolmap")) assert.Equal(map[string]int{}, c.koanf.IntMap("xxxx")) // Float. assert.Equal(float64(0), c.koanf.Float64("xxx")) assert.Equal(float64(1234), c.koanf.Float64("parent1.id")) assert.Equal([]float64{}, c.koanf.Float64s("xxxx")) assert.Equal([]float64{1, 2, 3}, c.koanf.Float64s("parent1.child1.grandchild1.ids")) assert.Equal(map[string]float64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Float64Map("parent1.intmap")) assert.Equal(map[string]float64{"key1": 1.1, "key2": 1.2, "key3": 1.3}, c.koanf.Float64Map("parent1.floatmap")) assert.Equal(map[string]float64{}, c.koanf.Float64Map("parent1.boolmap")) assert.Equal(map[string]float64{}, c.koanf.Float64Map("xxxx")) // String and bytes. assert.Equal([]byte{}, c.koanf.Bytes("xxxx")) assert.Equal([]byte("parent1"), c.koanf.Bytes("parent1.name")) assert.Equal("", c.koanf.String("xxxx")) assert.Equal("parent1", c.koanf.String("parent1.name")) assert.Equal([]string{}, c.koanf.Strings("xxxx")) assert.Equal([]string{"red", "blue", "orange"}, c.koanf.Strings("orphan")) assert.Equal(map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, c.koanf.StringMap("parent1.strmap")) assert.Equal(map[string][]string{"key1": {"val1", "val2", "val3"}, "key2": {"val4", "val5"}}, c.koanf.StringsMap("parent1.strsmap")) assert.Equal(map[string]string{}, c.koanf.StringMap("xxxx")) assert.Equal(map[string]string{}, c.koanf.StringMap("parent1.intmap")) // Bools. assert.Equal(false, c.koanf.Bool("xxxx")) assert.Equal(false, c.koanf.Bool("type")) assert.Equal(true, c.koanf.Bool("parent1.child1.grandchild1.on")) assert.Equal(true, c.koanf.Bool("strbool")) assert.Equal([]bool{}, c.koanf.Bools("xxxx")) assert.Equal([]bool{true, false, true}, c.koanf.Bools("bools")) assert.Equal([]bool{true, false, true}, c.koanf.Bools("intbools")) assert.Equal([]bool{true, true, false}, c.koanf.Bools("strbools")) assert.Equal(map[string]bool{"ok1": true, "ok2": true, "notok3": false}, c.koanf.BoolMap("parent1.boolmap")) assert.Equal(map[string]bool{"key1": true, "key2": true, "key3": true}, c.koanf.BoolMap("parent1.intmap")) assert.Equal(map[string]bool{}, c.koanf.BoolMap("xxxx")) // Others. assert.Equal(time.Duration(1234), c.koanf.Duration("parent1.id")) assert.Equal(time.Duration(0), c.koanf.Duration("xxxx")) assert.Equal(time.Second*3, c.koanf.Duration("duration")) assert.Equal(time.Time{}, c.koanf.Time("xxxx", "2006-01-02")) assert.Equal(time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), c.koanf.Time("time", "2006-01-02")) assert.Equal([]string{}, c.koanf.MapKeys("xxxx"), "map keys mismatch") assert.Equal([]string{"bools", "duration", "empty", "intbools", "negative_int", "orphan", "parent1", "parent2", "strbool", "strbools", "time", "type"}, c.koanf.MapKeys(""), "map keys mismatch") assert.Equal([]string{"key1", "key2", "key3"}, c.koanf.MapKeys("parent1.strmap"), "map keys mismatch") // Attempt to parse int=1234 as a Unix timestamp. assert.Equal(time.Date(1970, 1, 1, 0, 20, 34, 0, time.UTC), c.koanf.Time("parent1.id", "").UTC()) } } func TestMustGetTypes(t *testing.T) { assert := assert.New(t) for _, c := range cases { // Int. assert.Panics(func() { c.koanf.MustInt64("xxxx") }) assert.Equal(int64(1234), c.koanf.MustInt64("parent1.id")) assert.Equal(int64(-1234), c.koanf.MustInt64("negative_int")) assert.Panics(func() { c.koanf.MustInt("xxxx") }) assert.Equal(int(1234), c.koanf.MustInt("parent1.id")) assert.Equal(int(-1234), c.koanf.MustInt("negative_int")) assert.Panics(func() { c.koanf.MustInt64s("xxxx") }) assert.Equal([]int64{1, 2, 3}, c.koanf.MustInt64s("parent1.child1.grandchild1.ids")) assert.Panics(func() { c.koanf.MustInt64Map("xxxx") }) assert.Equal(map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustInt64Map("parent1.intmap")) assert.Panics(func() { c.koanf.MustInt64Map("parent1.boolmap") }) assert.Equal(map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustInt64Map("parent1.floatmap")) assert.Panics(func() { c.koanf.MustInts("xxxx") }) assert.Equal([]int{1, 2, 3}, c.koanf.MustInts("parent1.child1.grandchild1.ids")) assert.Panics(func() { c.koanf.MustIntMap("xxxx") }) assert.Panics(func() { c.koanf.MustIntMap("parent1.boolmap") }) assert.Equal(map[string]int{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustIntMap("parent1.intmap")) // Float. assert.Panics(func() { c.koanf.MustInts("xxxx") }) assert.Equal(float64(1234), c.koanf.MustFloat64("parent1.id")) assert.Panics(func() { c.koanf.MustFloat64s("xxxx") }) assert.Equal([]float64{1, 2, 3}, c.koanf.MustFloat64s("parent1.child1.grandchild1.ids")) assert.Panics(func() { c.koanf.MustFloat64Map("xxxx") }) assert.Panics(func() { c.koanf.MustFloat64Map("parent1.boolmap") }) assert.Equal(map[string]float64{"key1": 1.1, "key2": 1.2, "key3": 1.3}, c.koanf.MustFloat64Map("parent1.floatmap")) assert.Equal(map[string]float64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustFloat64Map("parent1.intmap")) // String and bytes. assert.Panics(func() { c.koanf.MustBytes("xxxx") }) assert.Equal([]byte("parent1"), c.koanf.MustBytes("parent1.name")) assert.Panics(func() { c.koanf.MustString("xxxx") }) assert.Equal("parent1", c.koanf.MustString("parent1.name")) assert.Panics(func() { c.koanf.MustStrings("xxxx") }) assert.Equal([]string{"red", "blue", "orange"}, c.koanf.MustStrings("orphan")) assert.Panics(func() { c.koanf.MustStringMap("xxxx") }) assert.Panics(func() { c.koanf.MustStringMap("parent1.intmap") }) assert.Equal(map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, c.koanf.MustStringMap("parent1.strmap")) assert.Equal(map[string][]string{"key1": {"val1", "val2", "val3"}, "key2": {"val4", "val5"}}, c.koanf.MustStringsMap("parent1.strsmap")) // // Bools. assert.Panics(func() { c.koanf.MustBools("xxxx") }) assert.Equal([]bool{true, false, true}, c.koanf.MustBools("bools")) assert.Equal([]bool{true, false, true}, c.koanf.MustBools("intbools")) assert.Equal([]bool{true, true, false}, c.koanf.MustBools("strbools")) assert.Panics(func() { c.koanf.MustBoolMap("xxxx") }) assert.Equal(map[string]bool{"ok1": true, "ok2": true, "notok3": false}, c.koanf.MustBoolMap("parent1.boolmap")) assert.Equal(map[string]bool{"key1": true, "key2": true, "key3": true}, c.koanf.MustBoolMap("parent1.intmap")) // Others. assert.Panics(func() { c.koanf.MustDuration("xxxx") }) assert.Equal(time.Duration(1234), c.koanf.MustDuration("parent1.id")) assert.Equal(time.Second*3, c.koanf.MustDuration("duration")) assert.Equal(time.Duration(-1234), c.koanf.MustDuration("negative_int")) assert.Panics(func() { c.koanf.MustTime("xxxx", "2006-01-02") }) assert.Equal(time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), c.koanf.MustTime("time", "2006-01-02")) // // Attempt to parse int=1234 as a Unix timestamp. assert.Panics(func() { c.koanf.MustTime("time", "2006") }) assert.Equal(time.Date(1970, 1, 1, 0, 20, 34, 0, time.UTC), c.koanf.MustTime("parent1.id", "").UTC()) } } func TestDelete(t *testing.T) { assert := assert.New(t) for _, c := range cases { c.koanf.Delete("parent2.child2.grandchild2") assert.Equal(false, c.koanf.Exists("parent2.child2.grandchild2.on")) assert.Equal(false, c.koanf.Exists("parent2.child2.grandchild2.ids.5")) assert.Equal(true, c.koanf.Exists("parent2.child2.name")) c.koanf.Delete("") assert.Equal(false, c.koanf.Exists("duration")) assert.Equal(false, c.koanf.Exists("empty")) } } func TestGetStringsMap(t *testing.T) { assert := assert.New(t) k := koanf.New(delim) k.Load(confmap.Provider(map[string]interface{}{ "str": map[string]string{ "k1": "value", }, "strs": map[string][]string{ "k1": {"value"}, }, "iface": map[string]interface{}{ "k2": "value", }, "ifaces": map[string][]interface{}{ "k2": {"value"}, }, "ifaces2": map[string]interface{}{ "k2": []interface{}{"value"}, }, "ifaces3": map[string]interface{}{ "k2": []string{"value"}, }, }, "."), nil) assert.Equal(map[string]string{"k1": "value"}, k.StringMap("str"), "types don't match") assert.Equal(map[string]string{"k2": "value"}, k.StringMap("iface"), "types don't match") assert.Equal(map[string][]string{"k1": {"value"}}, k.StringsMap("strs"), "types don't match") assert.Equal(map[string][]string{"k2": {"value"}}, k.StringsMap("ifaces"), "types don't match") assert.Equal(map[string][]string{"k2": {"value"}}, k.StringsMap("ifaces2"), "types don't match") assert.Equal(map[string][]string{"k2": {"value"}}, k.StringsMap("ifaces3"), "types don't match") } koanf-providers-vault-v2.0.1/tests/maps_test.go000066400000000000000000000171361454017643500216530ustar00rootroot00000000000000package koanf_test import ( "testing" "github.com/knadh/koanf/maps" "github.com/stretchr/testify/assert" ) var testMap = map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, "key.with.dot": 456, }, }, "top": 789, "empty": map[string]interface{}{}, } var testMap2 = map[string]interface{}{ "list": []interface{}{ map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, }, "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, "top": 789, "empty": map[string]interface{}{}, } var testMap3 = map[string]interface{}{ "list": []interface{}{ map[string]interface{}{ "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, }, }, }, }, }, }, }, }, map[string]interface{}{ "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, }, }, }, }, "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, }, }, }, }, }, }, "top": 789, "child": map[string]interface{}{ "key": 123, "child": map[string]interface{}{ "key": 123, }, }, "empty": map[string]interface{}{}, } func TestFlatten(t *testing.T) { f, k := maps.Flatten(testMap, nil, delim) assert.Equal(t, map[string]interface{}{ "parent.child.key": 123, "parent.child.key.with.dot": 456, "top": 789, "empty": map[string]interface{}{}, }, f) assert.Equal(t, map[string][]string{ "parent.child.key": {"parent", "child", "key"}, "parent.child.key.with.dot": {"parent", "child", "key.with.dot"}, "top": {"top"}, "empty": {"empty"}, }, k) } func BenchmarkFlatten(b *testing.B) { for n := 0; n < b.N; n++ { maps.Flatten(testMap3, nil, delim) } } func TestUnflatten(t *testing.T) { m, _ := maps.Flatten(testMap, nil, delim) um := maps.Unflatten(m, delim) assert.NotEqual(t, um, testMap) m, _ = maps.Flatten(testMap2, nil, delim) um = maps.Unflatten(m, delim) assert.Equal(t, um, testMap2) } func TestIntfaceKeysToStrings(t *testing.T) { m := map[string]interface{}{ "list": []interface{}{ map[interface{}]interface{}{ "child": map[interface{}]interface{}{ "key": 123, }, }, map[interface{}]interface{}{ "child": map[interface{}]interface{}{ "key": 123, }, }, }, "parent": map[interface{}]interface{}{ "child": map[interface{}]interface{}{ "key": 123, }, }, "top": 789, "empty": map[interface{}]interface{}{}, } maps.IntfaceKeysToStrings(m) assert.Equal(t, testMap2, m) } func TestMapMerge(t *testing.T) { m1 := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, "child2": map[string]interface{}{ "key": 123, }, }, "top": 789, "empty": map[string]interface{}{}, "key": 1, } m2 := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 456, "val": 789, }, }, "child": map[string]interface{}{ "key": 456, }, "newtop": 999, "empty": []int{1, 2, 3}, "key": "string", } maps.Merge(m2, m1) out := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 456, "val": 789, }, "child2": map[string]interface{}{ "key": 123, }, }, "child": map[string]interface{}{ "key": 456, }, "top": 789, "newtop": 999, "empty": []int{1, 2, 3}, "key": "string", } assert.Equal(t, out, m1) } func TestMapMerge2(t *testing.T) { src := map[string]interface{}{ "globals": map[string]interface{}{ "features": map[string]interface{}{ "testing": map[string]interface{}{ "enabled": false, }, }, }, } dest := map[string]interface{}{ "globals": map[string]interface{}{ "features": map[string]interface{}{ "testing": map[string]interface{}{ "enabled": true, "anotherKey": "value", }, }, }, } maps.Merge(src, dest) } func TestMergeStrict(t *testing.T) { m1 := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": "123", }, "child2": map[string]interface{}{ "key": 123, }, }, "top": 789, "empty": []int{}, "key": 1, } m2 := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 456, "val": 789, }, }, "child": map[string]interface{}{ "key": 456, }, "newtop": 999, "empty": []int{1, 2, 3}, "key": "string", } err := maps.MergeStrict(m2, m1) assert.Error(t, err) } func TestMapDelete(t *testing.T) { testMap := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, "key.with.dot": 456, }, }, "top": 789, "empty": map[string]interface{}{}, } testMap2 := map[string]interface{}{ "list": []interface{}{ map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, }, "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, "top": 789, "empty": map[string]interface{}{}, } maps.Delete(testMap, []string{"parent", "child"}) assert.Equal(t, map[string]interface{}{ "top": 789, "empty": map[string]interface{}{}, }, testMap) maps.Delete(testMap2, []string{"list"}) maps.Delete(testMap2, []string{"empty"}) assert.Equal(t, map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": 123, }, }, "top": 789, }, testMap2) } func TestSearch(t *testing.T) { assert.Equal(t, 123, maps.Search(testMap, []string{"parent", "child", "key"})) assert.Equal(t, map[string]interface{}{ "key": 123, "key.with.dot": 456, }, maps.Search(testMap, []string{"parent", "child"})) assert.Equal(t, 456, maps.Search(testMap, []string{"parent", "child", "key.with.dot"})) assert.Equal(t, 789, maps.Search(testMap, []string{"top"})) assert.Equal(t, map[string]interface{}{}, maps.Search(testMap, []string{"empty"})) assert.Nil(t, maps.Search(testMap, []string{"xxx", "xxx"})) } func TestCopy(t *testing.T) { mp := map[string]interface{}{ "parent": map[string]interface{}{ "child": map[string]interface{}{ "key": float64(123), "key.with.dot": float64(456), }, }, "top": float64(789), "empty": map[string]interface{}{}, } assert.Equal(t, mp, maps.Copy(mp)) } func TestLookupMaps(t *testing.T) { assert.Equal(t, map[string]bool{"a": true, "b": true}, maps.StringSliceToLookupMap([]string{"a", "b"})) assert.Equal(t, map[string]bool{}, maps.StringSliceToLookupMap(nil)) assert.Equal(t, map[int64]bool{1: true, 2: true}, maps.Int64SliceToLookupMap([]int64{1, 2})) assert.Equal(t, map[int64]bool{}, maps.Int64SliceToLookupMap(nil)) } koanf-providers-vault-v2.0.1/tests/posflag_test.go000066400000000000000000000060471454017643500223450ustar00rootroot00000000000000package koanf_test import ( "strings" "testing" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/providers/posflag" "github.com/knadh/koanf/v2" "github.com/spf13/pflag" "github.com/stretchr/testify/require" ) func posflagCallback(key string, value string) (string, interface{}) { return strings.ReplaceAll(key, "-", "_"), value } func TestLoad(t *testing.T) { assert := func(t *testing.T, k *koanf.Koanf) { require.Equal(t, k.String("key.one-example"), "val1") require.Equal(t, k.String("key.two_example"), "val2") require.Equal(t, k.Strings("key.strings"), []string{"1", "2", "3"}) require.Equal(t, k.Int("key.int"), 123) require.Equal(t, k.Ints("key.ints"), []int{1, 2, 3}) require.Equal(t, k.Float64("key.float"), 123.123) } fs := &pflag.FlagSet{} fs.String("key.one-example", "val1", "") fs.String("key.two_example", "val2", "") fs.StringSlice("key.strings", []string{"1", "2", "3"}, "") fs.Int("key.int", 123, "") fs.IntSlice("key.ints", []int{1, 2, 3}, "") fs.Float64("key.float", 123.123, "") k := koanf.New(".") require.Nil(t, k.Load(posflag.Provider(fs, ".", k), nil)) assert(t, k) // Test load with a custom flag callback. k = koanf.New(".") p := posflag.ProviderWithFlag(fs, ".", k, func(f *pflag.Flag) (string, interface{}) { return f.Name, posflag.FlagVal(fs, f) }) require.Nil(t, k.Load(p, nil), nil) assert(t, k) // Test load with a custom key, val callback. k = koanf.New(".") p = posflag.ProviderWithValue(fs, ".", k, func(key, val string) (string, interface{}) { if key == "key.float" { return "", val } return key, val }) require.Nil(t, k.Load(p, nil), nil) require.Equal(t, k.String("key.one-example"), "val1") require.Equal(t, k.String("key.two_example"), "val2") require.Equal(t, k.String("key.int"), "123") require.Equal(t, k.String("key.ints"), "[1,2,3]") require.Equal(t, k.String("key.float"), "") } func TestIssue90(t *testing.T) { exampleKeys := map[string]interface{}{ "key.one_example": "a struct value", "key.two_example": "b struct value", } fs := &pflag.FlagSet{} fs.String("key.one-example", "a posflag value", "") fs.String("key.two_example", "a posflag value", "") k := koanf.New(".") err := k.Load(confmap.Provider(exampleKeys, "."), nil) require.Nil(t, err) err = k.Load(posflag.ProviderWithValue(fs, ".", k, posflagCallback), nil) require.Nil(t, err) require.Equal(t, exampleKeys, k.All()) } func TestIssue100(t *testing.T) { var err error f := &pflag.FlagSet{} f.StringToString("string", map[string]string{"k": "v"}, "") f.StringToInt("int", map[string]int{"k": 1}, "") f.StringToInt64("int64", map[string]int64{"k": 2}, "") k := koanf.New(".") err = k.Load(posflag.Provider(f, ".", k), nil) require.Nil(t, err) type Maps struct { String map[string]string Int map[string]int Int64 map[string]int64 } maps := new(Maps) err = k.Unmarshal("", maps) require.Nil(t, err) require.Equal(t, map[string]string{"k": "v"}, maps.String) require.Equal(t, map[string]int{"k": 1}, maps.Int) require.Equal(t, map[string]int64{"k": 2}, maps.Int64) } koanf-providers-vault-v2.0.1/tests/textmarshal_test.go000066400000000000000000000052311454017643500232400ustar00rootroot00000000000000package koanf_test import ( "encoding" "fmt" "strings" "testing" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/structs" "github.com/knadh/koanf/v2" "github.com/stretchr/testify/assert" ) func TestTextUnmarshalStringFixed(t *testing.T) { defer func() { assert.Nil(t, recover()) }() type targetStruct struct { LogFormatPointer LogFormatPointer // default should map to json LogFormatValue LogFormatValue // default should map to json } target := &targetStruct{"text_custom", "text_custom"} before := *target var ( bptr interface{} = &(target.LogFormatPointer) cptr interface{} = target.LogFormatValue ) _, ok := (bptr).(encoding.TextMarshaler) assert.True(t, ok) _, ok = (cptr).(encoding.TextMarshaler) assert.True(t, ok) k := koanf.New(".") k.Load(structs.Provider(target, "koanf"), nil) k.Load(env.Provider("", ".", func(s string) string { return strings.Replace(strings.ToLower(s), "_", ".", -1) }), nil) // default values err := k.Unmarshal("", &target) assert.NoError(t, err) assert.Equal(t, &before, target) } // LogFormatValue is a custom string type that implements the TextUnmarshaler interface // Additionally it implements the TextMarshaler interface (value receiver) type LogFormatValue string // pointer receiver func (c *LogFormatValue) UnmarshalText(data []byte) error { switch strings.ToLower(string(data)) { case "", "json": *c = "json_custom" case "text": *c = "text_custom" default: return fmt.Errorf("invalid log format: %s", string(data)) } return nil } // value receiver func (c LogFormatValue) MarshalText() ([]byte, error) { //overcomplicated custom internal string representation switch c { case "", "json_custom": return []byte("json"), nil case "text_custom": return []byte("text"), nil } return nil, fmt.Errorf("invalid internal string representation: %q", c) } // LogFormatPointer is a custom string type that implements the TextUnmarshaler interface // Additionally it implements the TextMarshaler interface (pointer receiver) type LogFormatPointer string // pointer receiver func (c *LogFormatPointer) UnmarshalText(data []byte) error { switch strings.ToLower(string(data)) { case "", "json": *c = "json_custom" case "text": *c = "text_custom" default: return fmt.Errorf("invalid log format: %s", string(data)) } return nil } // also pointer receiver func (c *LogFormatPointer) MarshalText() ([]byte, error) { //overcomplicated custom internal string representation switch *c { case "", "json_custom": return []byte("json"), nil case "text_custom": return []byte("text"), nil } return nil, fmt.Errorf("invalid internal string representation: %q", *c) }