@cfxlabsinc/nx-secretsWorkspace-internal Nx plugin that infers the secrets-run, secrets-serve and secrets-build targets.
| Configuration | Source |
|---|---|
local (default) |
dev's SSM parameters, then the project's committed <projectRoot>/local.env, then the ambient environment; empty final values removed |
local-offline |
the project's committed <projectRoot>/local.offline.env of dummies in place of SSM, then local.env, then the ambient environment; the app gets dummy AWS keys |
dev / prod |
the app's config namespaces and /cfx/secrets/<app>/ in SSM, read by tools/secrets/run.ts |
Every configuration runs the inner command through the wrapper:
bun tools/secrets/run.ts --app <slug> --config <local|local-offline|dev|prod> [--env-file <path>] [--offline-env-file <path>] -- <cmd…>
The wrapper reads, for each namespace in the app's config list (WORKLOAD_CONFIGS in workloadConfig.ts), every parameter directly under /cfx/secrets/<ns>/ and /cfx/stack/<stage>/<ns>/ (stage dev for local), then under /cfx/secrets/<slug>/ for the keys the app still holds there; a later path wins, and a slug with no config list (ci) reads only its own path. Every read is non-recursive (branch configs sit one level deeper) and keeps the key's full name, so a local.env works unchanged. It uses the workload-dev (local, dev) or workload-prod profile (always that profile, whatever AWS_PROFILE the shell exports; the run fails if the parameters it returns are not in that configuration's account), sets NX_LOAD_DOT_ENV_FILES=false so an inner nx loads no dotenv files, and spawns the command with inherited stdio. It propagates the exit code and SIGINT / SIGTERM. An empty path is not an error.
For local the order is SSM < local.env < the ambient environment, and then every key whose final value is the empty string is removed, so KEY= in a local.env unsets a dev key. A missing --env-file is not an error. A local run needs aws sso login --sso-session cfx. local-offline reads local.offline.env instead of SSM and fails when the file is missing (see docs/SECRETS.md). For dev and prod the stored values win over the ambient environment and no file is read.
local.env is committed and holds only non-secret local overrides (localhost URLs, ports, flags). It must never hold a secret: tools/ci/env-local.test.ts fails on a secret-named key with a value (DB_PASSWORD excepted) and on a URL with credentials for a non-local host. It is not named .env.local because nx, Next and bun load that name on their own, into dev and prod runs too.
<slug> is the project name by default (secretsApp: "{projectName}"). A project whose SSM path differs sets secretsApp in its own project.json — db → aurora-db, fed-directory-services → fed-directory-api, solana-services → solana-api, and the services that run in the worker → temporal-worker.
secrets-runInferred for any project whose scripts/ directory holds at least one .ts / .mts / .mjs / .js file:
bun nx secrets-run <pkg> --args.script=<file> # dev (default)
bun nx secrets-run <pkg> --args.script=<file> -c local # local | local-offline | dev | prod
The command is bun {projectRoot}/scripts/{args.script}. A project without a scripts/ directory has nothing it could run, so it gets no target.
secrets-serve and secrets-buildBoth wrap an existing target — nx serve <pkg> and nx build <pkg> — so each is inferred only where that target exists:
bun nx secrets-build <pkg> # local (default)
bun nx secrets-build <pkg> -c prod # local | local-offline | dev | prod
secrets-serve also sets SENTRY_ENVIRONMENT=local. The variable comes from each stack's pulumi program rather than from the secrets, and the services' Sentry gates report when it is unset, so without it a laptop run with a SENTRY_DSN lands in the production issue stream.
An Nx plugin cannot see another plugin's inferred targets, so the presence check has three branches:
Source of build / serve |
How it is detected |
|---|---|
@cfxlabsinc/nx-lambda |
isLambdaProject() — src/lambda.ts + src/main.ts |
@cfxlabsinc/nx-open-next |
isOpenNextProject() — open-next.config.ts |
the project's own project.json |
reading targets[<name>] |
The dashboards declare serve in project.json purely to override the port, so the last branch alone would infer secrets-serve and miss secrets-build.
Registered in workspace nx.json, excluding the vendored Pulumi provider SDKs:
{
"plugin": "@cfxlabsinc/nx-secrets",
"options": {},
"exclude": ["packages/pulumi/sdks/*/**"]
}
A targetDefaults entry for these targets would outrank the inferred target and clobber it. See @cfxlabsinc/nx-lambda.
Resolves through the workspace dependency in the root package.json:
"@cfxlabsinc/nx-secrets": "workspace:*"