conflata

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2026 License: MIT Imports: 13 Imported by: 0

README

Conflata

Go Reference Go Report Card CI Coverage

Conflata is a Go configuration library that loads struct fields from environment variables first and falls back to external providers (AWS Secrets Manager, HashiCorp Vault, Google Secret Manager, or custom providers). It automatically decodes primitives and structured types and reports aggregated field errors so callers can decide how to handle missing values.

Installation

go get github.com/djbozjr/conflata

Quick Start

type Config struct {
    DatabaseURL string        `conflata:"env:DATABASE_URL provider:database-url backend:vault"`
    PoolSize    int           `conflata:"env:DB_POOL_SIZE"`
    Timeout     time.Duration `conflata:"env:DB_TIMEOUT"`
}

loader := conflata.New(
    conflata.WithProvider("vault", vaultProvider),
    conflata.WithDefaultProvider("vault"),
)

var cfg Config
if err := loader.Load(context.Background(), &cfg); err != nil {
    if group, ok := err.(*conflata.ErrorGroup); ok {
        for _, fe := range group.Fields() {
            log.Printf("field %s failed: %v", fe.FieldPath, fe.Attempts)
        }
    } else {
        log.Fatalf("invalid target: %v", err)
    }
}

Loader.Load prefers environment variables when set. If a value is missing, it queries the configured provider and, when failures occur, returns an *conflata.ErrorGroup so you can inspect and handle them.

Struct Tags

Describe how a field should be populated using the conflata tag:

conflata:"env:DATABASE_URL provider:prod/database backend:vault format:json"
Key Description
env Environment variable to read first.
provider Remote secret identifier (Vault path, AWS secret name, GCP secret).
backend Provider registration name. Defaults to aws unless overridden with WithDefaultProvider.
format Decoder to use (json, xml, text, or custom formats registered via WithDecoder).
default Literal fallback value used when both env and provider fail or are omitted. Quote values containing spaces, e.g. default:"my name"
optional When true, missing environment values do not produce an error. Provider/decode failures still surface.

At least one of env or provider must be present. Environment values override provider values when both succeed.

Advanced Usage
  • Nested structs: Tag an entire struct field (e.g. API APISettings "conflata:\"env:API_JSON provider:api/settings\"") to hydrate JSON/XML payloads while still allowing nested fields to declare their own tags (e.g. API.Token).
  • Selective loading: Fields without a conflata tag are skipped entirely—only tag the fields you want Conflata to manage.
  • Custom decoders: Register new formats with WithDecoder and reference them in tags, or set a new default decoder globally with WithDefaultFormat.
  • Defaults: Provide default:"literal" on any field to supply a fallback when env/provider values are absent.
  • Provider namespacing: Use WithProviderPrefix/WithProviderSuffix to dynamically prepend/append identifiers (e.g., environment names) to provider keys before lookup.
  • Custom providers: Implement the conflata.Provider interface and register instances via WithProvider.
  • Error inspection: Loader.Load returns an *ErrorGroup. Iterate the grouped FieldErrors to determine which configuration values failed and why without aborting the entire load.
Decoding

Conflata automatically chooses a decoder:

  • Primitives (string, numeric types, booleans, time.Duration, []byte) parse from plain text.
  • Structs, slices, arrays, maps, and interfaces default to JSON.
  • Pointer fields are allocated as needed.

Override with the format: tag or global WithDefaultFormat.

Errors

When Loader.Load returns an error, type assert it to *conflata.ErrorGroup. Each group exposes Fields() containing the attempted sources (environment, provider, decoder) per field so you can decide whether to continue with partial configuration or fail fast.

Custom Providers

Any type implementing Fetch(ctx context.Context, key string) (string, error) can be registered via WithProvider. Built-in providers for AWS Secrets Manager, Vault KV v2, and Google Secret Manager live under providers/.

Examples

The examples/ directory contains runnable programs for AWS, GCP, and Vault. Each demonstrates nested struct loading and includes stub providers when CONFLATA_EXAMPLE_STUB=1.

cd examples/aws
go run .

CONFLATA_EXAMPLE_STUB=1 go run ./examples/gcp

Providers

AWS Secrets Manager
smClient := secretsmanager.NewFromConfig(cfg)
awsProvider, _ := awssm.New(smClient)
loader := conflata.New(
    conflata.WithProvider("aws", awsProvider),
    conflata.WithDefaultProvider("aws"),
)

Environment requirements: standard AWS credential chain (env vars, shared config, metadata). Ensure IAM permissions for Secrets Manager.

HashiCorp Vault
client, _ := vaultapi.NewClient(vaultapi.DefaultConfig())
vaultProvider, _ := vault.FromClient(client, "secret")

Environment requirements: VAULT_ADDR plus a token (via VAULT_TOKEN, AppRole, or agent). Conflata automatically inspects KV data maps and falls back to JSON if no value key exists.

Google Secret Manager
client, _ := secretmanager.NewClient(ctx)
gcpProvider, _ := gcpsecret.New(client, gcpsecret.WithProject("my-project"))

Environment requirements: Application Default Credentials (service account JSON via GOOGLE_APPLICATION_CREDENTIALS, gcloud auth application-default login, or running on GCP runtimes).

Secret Payload Formats

Structured fields default to JSON unless another format or decoder is specified.

Field Payload Example
DatabaseCredentials struct {"username":"app","password":"s3cr3t"}
[]string ["primary","replica"]
CacheSettings with custom kv decoder enabled=true,ttl=30s
time.Duration 5s

Vault KV mounts can either store individual keys per field or a JSON blob per nested struct. See the examples for both approaches.

Testing

GOCACHE=$(pwd)/.gocache go test ./...

Development

gofmt -w .
GOCACHE=$(pwd)/.gocache go test ./...
GOCACHE=$(pwd)/.gocache go vet ./...
staticcheck ./...

Install Staticcheck with go install honnef.co/go/tools/cmd/staticcheck@latest. Releases follow semantic versioning; run ./scripts/release.sh v1.0.0 and git push origin v1.0.0 to tag a release.

Documentation

Overview

Package conflata loads configuration structs by reading environment variables first and falling back to external secret providers such as AWS Secrets Manager, HashiCorp Vault, or Google Secret Manager. Fields are annotated with `conflata` struct tags that describe which env/providor keys to read, and the loader reports grouped errors so callers can decide how to handle missing values.

Example:

type Config struct {
    DatabaseURL string `conflata:"env:DATABASE_URL provider:prod/database-url"`
}

loader := conflata.New(conflata.WithProvider("aws", awsProvider))
if err := loader.Load(ctx, &cfg); err != nil {
    if group, ok := err.(*conflata.ErrorGroup); ok {
        log.Println(group)
    } else {
        log.Fatal(err)
    }
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AttemptError

type AttemptError struct {
	Source     ValueSource
	Identifier string
	Err        error
}

AttemptError captures metadata about a failed attempt (environment lookup, provider fetch, decode) that occurred while resolving a single field.

func (AttemptError) Error

func (a AttemptError) Error() string

Error implements the error interface.

type DecodeFunc

type DecodeFunc func(raw string, targetType reflect.Type) (any, error)

type EnvLookupFunc

type EnvLookupFunc func(string) (string, bool)

EnvLookupFunc describes how to look up environment variables. Override with WithEnvLookup when running in custom environments.

type ErrorGroup

type ErrorGroup struct {
	// contains filtered or unexported fields
}

ErrorGroup groups field errors discovered during a loader run. The group can be inspected to understand which fields failed and why.

func (*ErrorGroup) Error

func (g *ErrorGroup) Error() string

Error implements the error interface.

func (*ErrorGroup) Fields

func (g *ErrorGroup) Fields() []FieldError

Fields returns a copy of the underlying FieldError slice for inspection.

func (*ErrorGroup) Has

func (g *ErrorGroup) Has() bool

Has reports whether the group contains any field errors.

type FieldError

type FieldError struct {
	FieldPath string
	Attempts  []AttemptError
}

FieldError aggregates all failed attempts for a field. When a field cannot be satisfied it may record multiple AttemptErrors that callers can inspect to decide how to handle the failure.

func (FieldError) Error

func (f FieldError) Error() string

Error implements the error interface.

type Loader

type Loader struct {
	// contains filtered or unexported fields
}

Loader populates configuration structs from environment variables and external providers according to the struct tags.

func New

func New(opts ...Option) *Loader

New constructs a Loader with optional functional options.

func (*Loader) Load

func (l *Loader) Load(ctx context.Context, target any) error

Load populates the provided struct pointer with configuration data. When one or more fields fail to load, the returned error will be an *ErrorGroup that can be inspected for per-field failures. Other fatal errors (such as passing a non-struct pointer) are returned directly.

type Option

type Option func(*Loader)

Option configures the Loader.

func WithDecoder

func WithDecoder(name string, fn DecodeFunc) Option

WithDecoder registers a custom format decoder keyed by name. Struct tags can then reference the decoder via `format:decoder`.

func WithDefaultFormat

func WithDefaultFormat(name string) Option

WithDefaultFormat overrides the default decoder used for structured types when no per-field format is provided.

func WithDefaultProvider

func WithDefaultProvider(name string) Option

WithDefaultProvider picks which registered provider should be used when a tag does not specify a backend explicitly.

func WithEnvLookup

func WithEnvLookup(fn EnvLookupFunc) Option

WithEnvLookup overrides the environment variable lookup strategy.

func WithProvider

func WithProvider(name string, provider Provider) Option

WithProvider registers a provider under the supplied name so struct tags can reference it via the `backend:` key.

func WithProviderPrefix added in v1.1.0

func WithProviderPrefix(fn func() string) Option

WithProviderPrefix supplies a function whose result is prepended to provider keys prior to lookup (for example to inject environment names).

func WithProviderSuffix added in v1.1.0

func WithProviderSuffix(fn func() string) Option

WithProviderSuffix supplies a function whose result is appended to provider keys prior to lookup.

type Provider

type Provider interface {
	Fetch(ctx context.Context, key string) (string, error)
}

Provider fetches configuration values from an external system such as Vault, AWS Secrets Manager, or GCP Secret Manager. Custom providers can be registered with WithProvider.

type ValueSource

type ValueSource string

ValueSource identifies where a configuration value was attempted to be read from (environment, provider, decoder, tag parsing, etc.).

const (
	SourceEnv      ValueSource = "env"
	SourceProvider ValueSource = "provider"
	SourceDecoder  ValueSource = "decoder"
	SourceTag      ValueSource = "tag"
)

Directories

Path Synopsis
examples
aws command
gcp command
vault command
providers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL