feat(providers): general ?layout=flat setting to resolve at the store root - #183
Closed
ojhermann wants to merge 1 commit into
Closed
feat(providers): general ?layout=flat setting to resolve at the store root#183ojhermann wants to merge 1 commit into
ojhermann wants to merge 1 commit into
Conversation
ojhermann
force-pushed
the
feat/infisical-flat-layout
branch
from
July 20, 2026 21:11
d070f6e to
56bae9a
Compare
… root
Maps SecretSpec's {project}/{profile}/{key} convention onto the store root:
the secret is addressed by key alone, dropping the secretspec/{project}/{profile}
scaffolding but keeping any provider-native container (a Vault mount) or user
prefix (an AWS ?prefix=, an Infisical ?path=). The default nested layout is
unchanged.
Honored by every hierarchical provider -- Infisical, Vault, OpenBao, AWS Secrets
Manager, Google Cloud Secret Manager and Azure Key Vault. Providers with no
hierarchy (dotenv, env, bws) are already flat and ignore it.
Layout is a shared, per-provider-instance setting: parsed once through a strict
ProviderUrl::layout() (nested/flat, unknown value errors), then honored by each
provider's convention_address in its own dialect, so it works correctly in
fallback chains. Vault and OpenBao pick it up through their shared KV core, so
each product's URI carries it under its own scheme. Flat addresses by key alone,
so project/profile aren't validated; where the backend constrains names the key
must fit, and Azure Key Vault -- which uses the key verbatim -- refuses an
underscore the nested layout would have Base32-encoded away. Dropping the
profile gives up profile separation unless the provider pins its environment
another way (an Infisical ?env=); flat plus such a pin collapses every profile
onto one key deliberately.
Resolves #181.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ojhermann
force-pushed
the
feat/infisical-flat-layout
branch
from
July 22, 2026 16:14
56bae9a to
39ba748
Compare
ojhermann
marked this pull request as ready for review
July 22, 2026 16:14
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.
Resolves #181. This started as an Infisical-only
?layout=flat(raised by @nickdichev migrating from BWS); per @domenkozar's suggestion it is now a general provider setting, since the namespaced-vs-root question is the same for every hierarchical backend.What this adds
?layout=flatmaps SecretSpec's{project}/{profile}/{key}convention onto the store root — the secret is addressed by key alone, dropping thesecretspec/{project}/{profile}scaffolding but keeping any provider-native container (a Vault mount) or user prefix (an AWS?prefix=, an Infisical?path=). The default nested layout is unchanged, so existing configs behave exactly as before.Honored by Infisical, Vault, OpenBao, AWS Secrets Manager, Google Cloud Secret Manager, and Azure Key Vault. Providers with no hierarchy (
dotenv,env,bws) are already flat and ignore it.Design
ProviderUrl::layout()(strict:nested/flat; an unknown value errors, like?tls=). Each provider'sconvention_addressthen honors it in its own dialect. Layout is per-provider-instance, so it works correctly in per-secret fallback chains (a flat provider alongside a nested one).KvConfig/KvProvidercore added in feat(openbao): add first-class OpenBao provider #187, so each product carries it under its own scheme with no duplicated logic.?env=) still keeps them apart, but flat plus a pinned env collapses every profile onto one key — a deliberate, documented "you're giving up profile separation" mode.The two questions this PR previously left open
Both are now decided, so this is a concrete proposal rather than a fork in the road. Reasoning below in case you'd steer either differently.
Mechanism: a URI query param
Chosen:
?layout=in the provider URI. The deciding argument is per-secret fallback chains —providers = ["flat_vault", "keyring"]puts two provider instances side by side, and layout has to be describable per instance to express that. It also needs no answer to "what configures an inline--provider vault://...on the CLI", since the URI is the only thing such an invocation has.Considered and deliberately not built: a
layoutfield on the provider alias.ProviderAliasalready takes a table form ({ uri = "...", credentials = { ... } }), solayout = "flat"would fit structurally, and it would be more discoverable and more typo-checkable than a query string. What stopped me is that it buys no expressive power the URI doesn't already have — the alias is written once either way — while adding a second way to say the same thing, a precedence rule, and a disagreement case (uri = "...?layout=flat"next tolayout = "nested"— silent precedence, or a load error?).The larger question underneath, which is the one I'd actually value your steer on: should provider settings live in the alias table at all? If they should, the coherent move is to lift
?layout=,?kv=,?auth=,?prefix=there together as a design, not to special-case one setting first — and layout is the least representative example to prejudge it with. Happy to go either way; I just didn't want to answer that question by accident.Spelling:
?layout=flat/?layout=nestedChosen: an enum, matching the existing enum-valued
?kv=and?auth=style, with unknown values rejected rather than guessed.Considered:
?flat=true— shorter and reads more naturally, but it's a boolean where the concept is really a choice of naming scheme. A third layout later (say, one that drops the profile but keeps the project) would need a new parameter and an awkward interaction with this one, where?layout=just gains a variant.Tests & docs
Per-provider unit tests (no HTTP mocks): flat addressing, unconstrained project/profile names, key-still-validated, URI round-trip, unknown-layout rejected. Full crate suite green (588 tests);
fmt/clippyclean. Docs updated across the providers reference (a general Layout section) and each provider page — including the new OpenBao guide — labeled0.17+.Rebased on current
main, after #187 landed.🤖 Generated with Claude Code