You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We have basic secrets today (fallout :secrets, v1:-encrypted values in parameters.json — see #212 for the audit). It's a storage mechanism: put secrets in the file, the build reads them via [Parameter] [Secret] readonly string ApiKey;.
We don't have a first-class variable layer — non-secret named values that can be:
Defined once per repo (or per profile / environment) in a structured way.
Substituted into other parameter values, tool arguments, and CI config generators — e.g. apiUrl = "https://${env}.example.com/api" where ${env} resolves from a variable.
Sourced from layered config (build defaults → repo profile → environment override → CLI arg), with clear precedence.
Variables and secrets go together:
Both are named values configured per repo/profile/environment.
Both want the same substitution syntax (${name} in tool args, CI config, artifact paths).
Same resolution order: command-line > env var > profile > default.
Only difference: is the value sensitive. Secrets get encrypted at rest, redacted in logs, never echoed into CI config.
Treating them as one feature with a Sensitive=true flag (not two parallel mechanisms) keeps the mental model small.
Works, but every consumer reinvents interpolation, and [GitHubActions]-generated workflows can't express "use this variable in the step args" — it's hardcoded at gen-time.
and reference ${ApiUrl} from a tool argument, a CI step's env: block, an artifact path. The resolver handles substitution, layering, redaction.
Open design questions
Substitution syntax.${name}, {{ name }}, <<name>>? Pick one and document it.
Where substitution happens. Parameter-injection time (so [Parameter] readonly string ApiUrl sees the resolved string)? Tool-invocation time? Both, with attribute opt-in?
Profile/environment layering. Partly exists via parameters.<name>.json profiles. Variables + secrets should follow it. Document the precedence chain.
CI-config generators. Do [GitHubActions] / [AzurePipelines] emit ${{ env.X }} placeholders the CI engine resolves, or resolve at gen-time? Probably placeholders for secrets (no leaking into committed YAML), gen-time for non-sensitive variables.
Plugin SDK touch points. v12 ships Fallout.Plugin.Sdk; variable resolvers and secret backends are natural extension points. Decide whether the variable subsystem ships before the SDK (internal seams) or as part of it (public seams).
Milestone
Maintainer pick:
v10.x — probably too late; this is a public-API addition.
v11 — plausible if scoped to internal substitution + a layered-config refactor that keeps the public API stable. Pairs with the foundation work (god-class split, internal IBuildMiddleware).
Context
We have basic secrets today (
fallout :secrets,v1:-encrypted values inparameters.json— see #212 for the audit). It's a storage mechanism: put secrets in the file, the build reads them via[Parameter] [Secret] readonly string ApiKey;.We don't have a first-class variable layer — non-secret named values that can be:
apiUrl = "https://${env}.example.com/api"where${env}resolves from a variable.Variables and secrets go together:
${name}in tool args, CI config, artifact paths).Treating them as one feature with a
Sensitive=trueflag (not two parallel mechanisms) keeps the mental model small.What "first-class" buys consumers
Today in C#:
Works, but every consumer reinvents interpolation, and
[GitHubActions]-generated workflows can't express "use this variable in the step args" — it's hardcoded at gen-time.First-class variables let you write:
and reference
${ApiUrl}from a tool argument, a CI step'senv:block, an artifact path. The resolver handles substitution, layering, redaction.Open design questions
${name},{{ name }},<<name>>? Pick one and document it.[Parameter] readonly string ApiUrlsees the resolved string)? Tool-invocation time? Both, with attribute opt-in?parameters.<name>.jsonprofiles. Variables + secrets should follow it. Document the precedence chain.[GitHubActions]/[AzurePipelines]emit${{ env.X }}placeholders the CI engine resolves, or resolve at gen-time? Probably placeholders for secrets (no leaking into committed YAML), gen-time for non-sensitive variables.secrets.VaultRef("my-org/api-key")resolved at injection time. Sketch the seam now even if backends land later.Fallout.Plugin.Sdk; variable resolvers and secret backends are natural extension points. Decide whether the variable subsystem ships before the SDK (internal seams) or as part of it (public seams).Milestone
Maintainer pick:
IBuildMiddleware).IVariableResolver,ISecretBackend) shipping withFallout.Plugin.Sdk. Pairs with Track external secret-manager integrations (1Password, Bitwarden, Vault, …) #168 and Implement CredentialStore for Windows (DPAPI) and Linux (libsecret) #180.Chris's call. Both defensible; v12 feels right for the public-API shape, but an internal v11 cut works if internal value is high enough.
Refs
src/Fallout.Utilities/Security/EncryptionUtility.cs+fallout :secrets(Program.Secrets.cs).docs/adr/0002-cross-provider-auth-and-secret-conventions.md.