Adding a source¶
Sources live under internal/provider/ and implement one interface:
type Provider interface {
Scheme() string // "example"
Description() string // "Example Secrets Service"
Validate(ref *template.Ref) error // offline checks, run by `validate`
Request(ref *template.Ref) Request // apply prefixes and defaults
Fetch(ctx context.Context, reqs []Request) (map[Request]Result, error)
}
What envhaul does for you¶
The resolver parses templates, collects every distinct Request for your
scheme across all components, and calls Fetch once with all of them. It then
handles #key JSON extraction, pipes, missing-value reporting and
--strict. Your provider only maps requests to values.
The built-in providers are good models: internal/provider/vault (plain HTTP
API), internal/provider/onepassword (wrapping a CLI) and
internal/provider/gcpsecrets (REST with OAuth credentials).
Guidelines¶
- Batch. Fetch as many values per API call as the service allows, and
bound concurrency (see
awsssmfor an example). - Missing isn't an error. Return
Result{Found: false}for values that don't exist. Return errors only for failures such as authentication, authorization or network problems, and say how to fix them. @profileis the user's way to pick credentials or an account. Map it to whatever the source uses (a Vault namespace, a 1Password account) and document it.- Never log values. Log identifiers at debug level only.
- Offline first.
ValidateandRequestmust work without network access;validateandlistrely on that.
Checklist¶
- A package
internal/provider/<name>with the provider and unit tests against a fake client interface. - Registration in
internal/providers/providers.go, and, if the source has settings, its block inconfig.SourceKeysandschema/envhaul.schema.json. - A testscript in
internal/cli/testdata/scriptif the CLI behavior changes. - An integration test in
test/integrationif an emulator exists. - Docs: a page under
docs/sources/, plus the table indocs/sources/index.md.