Context
@stackra/config resolves every @Secret("NAME") field through the SecretStore port. Wave 10 built two drivers
beside the runtime’s environment store (envSecrets in @stackra/app): InfisicalSecretStoreDriver (entry ., web
fetch, universal-auth machine identity) and AwsSecretsManagerSecretStoreDriver (entry ./node, the runtime’s AWS
role). Both read every named secret into memory at load() and answer get(name) synchronously. Nothing said which
deployment binds which driver, and the Infisical driver needs a credential of its own (INFISICAL_CLIENT_ID,
INFISICAL_CLIENT_SECRET) before it can read anything. 0173 already makes runway sync Infisical into Encore, Workers and
EAS, so a runtime that is synced does not need to call Infisical at all.
Decision
-
Three drivers, one per process. A server process binds exactly one
SecretStoredriver:env(the platform’s own store, read as the process environment or Worker bindings),infisicaloraws-secrets-manager. The choice is deployment data in the environment’srunway.yaml(secrets.store), never a branch in code. Clients (web, Expo, Electron) bind no server secret store; they read only public build values. -
Binding per deploy mode.
A synced SaaS runtime never calls Infisical at run time, so an Infisical outage cannot stop it.
-
The bootstrap credential. A process bound to
infisicalreads exactly two secrets from the platform’s own store:INFISICAL_CLIENT_IDandINFISICAL_CLIENT_SECRET, through theenvdriver, and buildsInfisicalConfigwith them (buildConfig(InfisicalConfig, { values, secrets: platform })). They are a machine identity per environment and service, read-only on that service’s folder. Runway’ssecrets syncwrites them into the platform store (a Kubernetes or Compose secret on-prem, by the customer’s operator when runway does not run there); no file in a repository, image or.envholds them. Where the platform gives a workload identity (an AWS role), that identity signs the reads and there is no bootstrap secret, which is why AWS compute bindsaws-secrets-manager. -
Load at boot, fail closed. The runtime awaits
load()before it builds any configuration; a failed load stops the process and names the step and status, never a value (both drivers already do this). A rotation reaches a process on the next deploy or an explicit reload; no driver polls. - Residency. Each product-region’s secrets live in that region’s account or project (0353, 0354); the sync never copies one region’s values into another.
-
Values. None of these is seed, pack, settings or rule-set data. The store choice, Infisical site, project,
environment and folder, and the AWS region and secret ids are deployment configuration in
runway.yaml; secret names are in git; values exist only in Infisical and the stores it syncs to (0173 d6).
Consequences
- SaaS keeps one rotation point (Infisical) and no run-time dependency on it.
- On-prem and air-gapped customers can run their own Infisical without any Figentra service.
- The AWS path needs a secret sync target per account; runway’s
secrets syncgains anaws-secrets-managerprovider. - A GCP-native Secret Manager driver is not built; GCP reads through
envuntil one is needed.
Enforcement
planned — the runway schema refuses an environment whosesecrets.store is not one of the three drivers, and refuses
infisical without the two bootstrap names in the environment’s secret list; the gitleaks scan of 0173 covers the
bootstrap names in files. Nothing checks it yet.
Open questions
- Infisical machine-identity auth on AWS. Infisical also offers AWS IAM auth, which would remove the bootstrap pair on AWS on-prem installs; the driver supports universal auth only.
- A GCP Secret Manager driver. Only if a GCP runtime cannot mount secrets as environment.
Supersedes and sources
Supersedes: none. Reads with 0173, 0146, 0179 and 0353. Sources:notes/handover/build-wave10-2026-10-25.md (runtime builder, question 1);
packages/foundation/config/README.md (secret store drivers); packages/runtime/app/src/core/functions/env-secrets.function.ts.