Skip to main content

Env vars and secrets with catladder

Environment variables are declared per component in catladder.ts; secret values are never checked into the repo.

Declaring variables​

components: {
app: {
vars: {
// names of secret vars — values are stored in the secrets vault, not in git
secret: ["API_KEY"],
public: {
MY_VAR: "some value",
// reference other vars, including from other components:
GRAPHQL_ENDPOINT: "${api:ROOT_URL}/graphql",
},
},
},
}

Predefined per component/env: ROOT_URL, HOSTNAME, PORT (plus deploy-type specific ones). All vars are available at build time and at runtime. After changing declarations, regenerate with yarn catenv and commit.

Setting secret values​

Secret values are managed through the catladder CLI — never by editing files in the repo. All secrets commands accept a scope: dev:web (one env of one component), dev: (one env, all components), :web (all envs of one component), or nothing (everything).

An env that shares another env's secrets (top-level environments.<name>.inherit, e.g. a next branch env inheriting from dev) has no secret store of its own — its jobs reference the source env's variables directly, so it never appears in secrets scopes: manage (and rotate) the values via the source env, which affects both.

Check what is declared and what is still unset (never prints values unless --reveal is passed):

yarn catladder project secrets-list
yarn catladder project secrets-list --check # non-zero exit when something is unset

Set a single secret (the usual case — also for rotating one value across all envs via the :component scope):

echo -n "the-value" | yarn catladder project secrets-set dev:web API_KEY
yarn catladder project secrets-set :web API_KEY --value-file /path/to/value

Prefer stdin or --value-file over --value so values stay out of shell history. Never pass a real secret value you found in the conversation without the user having provided it for this purpose.

Bulk-edit several secrets as a YAML document (component → env → key: value):

yarn catladder project secrets-pull dev: --out /tmp/secrets.yml   # unset ones appear as "🚨 FILL ME"
# edit the file, then:
yarn catladder project secrets-push dev: --file /tmp/secrets.yml # partial docs are fine

secrets-push skips placeholder/empty values, rejects undeclared keys, and may be partial — only the provided keys are written. Both support --key KEY1,KEY2 to narrow further. Delete the temp file afterwards; never commit it.

Humans may instead use the interactive editor flow (project config-secrets, opens $EDITOR); as an agent, use the commands above.

All of these write to the secrets vault (the source of truth) and automatically mirror to the enabled CI backends — which vault is configured makes no difference to the commands.

Provisioned secrets​

A few secrets are not typed in by a human but created by yarn catladder project setup: the gcloud deploy service account key (GCLOUD_DEPLOY_credentialsKey) and the kubernetes deploy credentials (KUBE_TOKEN, KUBE_CA_PEM, KUBE_URL). They travel the same route as every other secret — vault first, then the enabled CI backends — but they are hidden: they never show up in secrets-list, in the editor or in a pulled document, and they must never be set by hand.

Re-running project setup rotates them (a fresh credential is created and the old one revoked). That is also the answer whenever they are missing somewhere — after switching secrets.vault, for instance: a secrets-pull/secrets-push round trip does not carry hidden keys over, so re-run project setup to provision them into the new vault.

GitHub pipelines​

GitHub Actions cannot read the vault at runtime; secrets are mirrored into GitHub environment secrets (one GitHub environment per catladder env). Sync them with:

yarn catladder project secrets-sync-github

Run this after adding/changing secrets when a github pipeline is enabled.

Local development​

catenv generates the local env (.env files / exported vars via direnv) for the local environment. If a var is missing locally, check its declaration in catladder.ts and re-run yarn catenv before suspecting anything else.

Read-only cloud access for local use​

For google cloud run components, localAccess in catladder.ts (project default at the top level, per env in environments.<env>, false to disable) declares read-only access for local use, e.g. localAccess: { gcp: { presets: ["logs"] } }. catladder project setup creates a service account per component/env with exactly those roles and stores its key in the secret store under the local env (never mirrored to CI); catladder project doctor reports drift. catenv writes the key to .catladder/local-access/gcp-<env>-<component>.json (0600, gitignored) and exports its path as CATLADDER_LOCAL_ACCESS_GCP_<ENV>_KEY_FILE — not as GOOGLE_APPLICATION_CREDENTIALS, use it with an isolated CLOUDSDK_CONFIG, never gcloud auth on the personal config. The logs preset is roles/logging.viewer only (project-wide); extra roles must be roles/{logging,monitoring,errorreporting}.viewer (never roles/viewer/roles/run.viewer: cloud run revisions carry secrets as plain env vars), unless allowAnyRole: true (also needed for custom roles); write/admin roles are always rejected. Needs a non-CI vault (e.g. bitwarden) — project setup refuses with the gitlab vault. After a key rotation on another machine, run catenv --vault-mode refresh.

The vertex preset grants roles/aiplatform.user (to call Vertex AI models, e.g. local evals). It is not read-only: it can use and bill every Vertex AI API of the project and create/change/delete Vertex AI resources; it is only accepted as a preset, never in roles. Add credentialsEnvVar: "GOOGLE_APPLICATION_CREDENTIALS" (in one env only) to have catenv export the key path under that name as well, so google client libraries use it without gcloud auth application-default login. The variable lands in the component's .env (e.g. apps/web/.env), not in a root .env: scripts run from the repo root must load that file (node --env-file-if-exists=apps/web/.env …).

  • catladder-config — general catladder.ts structure and regeneration
  • catladder-builds — build-time vars (jobVars) and build config
  • catladder-deploys — runtime deploy config
  • catladder-pipelines — how the generated pipelines work
  • catladder-cli — non-interactive CLI usage and command reference
  • catladder-migrate-ci-backend — moving between CI backends (the vault is what blocks decommissioning the old one)