feat(loader): viper-backed shared config loader#50
Open
spbsoluble wants to merge 1 commit into
Open
Conversation
Introduces a new loader/ subpackage that resolves Keyfactor config
from layered sources (CLI flag > env > config file > defaults) and
returns a populated auth_providers.Server. Designed so multiple
Keyfactor Go tools (kfacme-cli, kfutil, terraform-provider-keyfactor,
future tools) can share the same env vars and the same
~/.keyfactor/command_config.{json,yml,yaml} layout, with each tool's
extension fields living in a named sub-block (e.g. acme:) under each
Server entry.
What this PR adds:
* New `loader/` subpackage. Viper is the only new transitive
dependency, and it stays scoped to this subpackage — consumers
that don't import loader keep their slim dep trees.
* `Loader` type with functional options: WithConfigFile, WithProfile,
WithFlagSet (for cobra/pflag integration), WithDefaults,
WithToolNamespace.
* File discovery preserves kfc-auth's existing convention: explicit
--config-file flag > WithConfigFile option > KEYFACTOR_AUTH_CONFIG_FILE
> ~/.keyfactor/command_config.{json,yaml,yml}.
* Profile selection: WithProfile > KEYFACTOR_AUTH_CONFIG_PROFILE >
DefaultConfigProfile ("default").
* Per-tool sub-blocks under each Server, decoded into caller-supplied
structs via Loader.DecodeExtras(namespace, target). Tool-namespaced
env vars (e.g. KEYFACTOR_ACME_BASE_URL → servers.<profile>.acme.base_url)
are bound by reflection over the schema struct's mapstructure tags.
* Override merge with strict mode: any auth-method-specific field set
in a sub-block forces the sub-block to declare the entire tuple;
partial overrides return a clear error naming the missing field.
This catches "I forgot client_secret" mistakes at load time rather
than at API call time. See ResolvedAuth() docs and the
partial_override.yaml fixture.
What this PR adds for the validation split (Phase 2, folded in):
* New `auth_providers.AuthCreds` type: the auth-only view of a
Server, decoupled from Command target fields (Host / Port /
APIPath). Lets callers validate credentials independently of
whether they're targeting Command, ACME, or anything else.
* `AuthCreds.Validate()` returns the resolved auth method
(basic / oauth2 / token / kerberos) or a structured error.
* `AuthCredsFromServer()` extracts the auth fields from a Server.
* Existing CommandAuthConfig.ValidateAuthConfig() is UNCHANGED in
signature and behavior — kfutil and terraform-provider keep
validating "auth + Command URL + reachability" exactly as before.
The new AuthCreds-only path is opt-in for callers that don't
target Command.
What this PR adds to the Server struct (additive, non-breaking):
* New `Extras map[string]any` field with `json:"-" yaml:"-"
mapstructure:",remain"`. The loader populates it with the unknown
keys at each Server entry. Existing JSON/YAML wire format is
unchanged because the tags exclude Extras from direct marshaling;
the loader handles sub-block decoding separately.
Tests:
* loader/loader_test.go covers shared-creds inheritance, separate-creds
override, ACME-only profile (no Host), mixed auth methods
per tool, partial-override rejection, profile selection,
env-var override, tool-namespace env binding, and the
AuthCreds.Validate matrix.
* Existing auth_providers tests continue to pass on the unchanged
code paths. Pre-existing Azure / config-format failures on
origin/release-v1.6 are unaffected by this PR.
Backward compatibility:
* Every existing exported symbol in auth_providers/ keeps its
signature.
* Server gains one field (Extras) with marshal-suppressing tags;
existing serialization paths produce identical output.
* No consumer is forced to import loader/ — opt-in adoption.
Follow-up work (separate PRs in other repos):
* kfacme-cli migrates internal/config to use loader/, with a one-time
~/.keyfactor/kfacme_config.json → ~/.keyfactor/command_config.yaml
migrator.
* kfutil wires its currently-defined-but-ignored flags through the
loader and retires its local ConfigurationFile mirror types.
* terraform-provider-keyfactor falls back to the loader when the
HCL provider block is incomplete.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
loader/subpackage so downstream Keyfactor Go tools (kfacme-cli, kfutil, terraform-provider-keyfactor, future tools) can share env vars and the same~/.keyfactor/command_config.{json,yml,yaml}layout. Each tool's extension fields live in a named sub-block (acme:,kfutil:) under eachServerentry. Folds in the auth/URL validation split.Highlights:
loader.Loaderwith functional options (WithConfigFile,WithProfile,WithFlagSet,WithDefaults,WithToolNamespace).KEYFACTOR_AUTH_CONFIG_PROFILE.Loader.DecodeExtras(namespace, target). Tool-namespaced env vars (e.g.KEYFACTOR_ACME_BASE_URL→servers.<profile>.acme.base_url) bound by reflection over the schema struct'smapstructuretags.partial_override.yamlfixture.auth_providers.AuthCredstype withValidate()decouples credential checks from Command target validation. ACME-only users (no Command access) no longer need to set Host/APIPath to use the same machinery.Servergains anExtrasfield with marshal-suppressing tags; existing JSON/YAML wire format unchanged.Backward compatibility
auth_providers/keeps its signature.CommandAuthConfig.ValidateAuthConfigis unchanged — kfutil and terraform-provider keep validating auth + Command URL + reachability exactly as before.loader/. Consumers that don't importloader/are unaffected.Follow-ups (separate PRs)
internal/configtoloader/, add one-time migrator for the old hyphen-keyedkfacme_config.json.ConfigurationFilemirror types.Test plan
go test ./loader/...clean. Pre-existing Azure-dependent failures onauth_providersare unaffected.v1.6.0-rc.0tagged on this branch's HEAD; kfacme-cli PR opens against that RC to prove end-to-end before this PR merges.Plan reference
Full design doc lives at
~/.claude/plans/shared-keyfactor-config-loader.md(not in repo) covering the architecture decisions, override semantics, env-var conventions, phasing, and migration story.