Skip to content

feat(loader): viper-backed shared config loader#50

Open
spbsoluble wants to merge 1 commit into
release-v1.6from
feat/loader-subpackage
Open

feat(loader): viper-backed shared config loader#50
spbsoluble wants to merge 1 commit into
release-v1.6from
feat/loader-subpackage

Conversation

@spbsoluble
Copy link
Copy Markdown
Collaborator

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 each Server entry. Folds in the auth/URL validation split.

Highlights:

  • loader.Loader with functional options (WithConfigFile, WithProfile, WithFlagSet, WithDefaults, WithToolNamespace).
  • Precedence: CLI flag > env > config file > caller defaults > zero values.
  • File discovery preserves kfc-auth's existing convention; profile selection honors KEYFACTOR_AUTH_CONFIG_PROFILE.
  • Per-tool sub-blocks decoded via Loader.DecodeExtras(namespace, target). Tool-namespaced env vars (e.g. KEYFACTOR_ACME_BASE_URLservers.<profile>.acme.base_url) bound by reflection over the schema struct's mapstructure tags.
  • Strict-mode override merge for credentials: any auth-method-specific field set in a sub-block forces it to declare the entire tuple. Partial overrides return a clear error naming the missing field. See partial_override.yaml fixture.
  • New auth_providers.AuthCreds type with Validate() 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.
  • Server gains an Extras field with marshal-suppressing tags; existing JSON/YAML wire format unchanged.

Backward compatibility

  • Every existing exported symbol in auth_providers/ keeps its signature.
  • CommandAuthConfig.ValidateAuthConfig is unchanged — kfutil and terraform-provider keep validating auth + Command URL + reachability exactly as before.
  • Viper is the only new transitive dep and stays scoped to loader/. Consumers that don't import loader/ are unaffected.
  • No consumer is forced to migrate.

Follow-ups (separate PRs)

  • kfacme-cli: migrate internal/config to loader/, add one-time migrator for the old hyphen-keyed kfacme_config.json.
  • kfutil: wire defined-but-ignored flags, retire local ConfigurationFile mirror types.
  • terraform-provider-keyfactor: fall back to loader when HCL provider block is incomplete.

Test plan

  • CI go_tests workflow passes.
  • go test ./loader/... clean. Pre-existing Azure-dependent failures on auth_providers are unaffected.
  • v1.6.0-rc.0 tagged 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.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant