Skip to content

Secrets

small-config is designed so that sensitive values (API keys, SSH public keys, tokens) are never written to disk — not to config.py, not to state files, not to rendered templates on disk beyond what's strictly necessary for the tool they're passed to.

How secrets work

Use sc.secret("name") in config.py to declare a secret reference:

from small_config import sc

ssh_pub_key = sc.secret("ssh_pub_key")
api_key     = sc.secret("stripe_api_key")

This returns a SecretRef object — a lazy reference. The actual value is not read yet.

When the engine resolves vars before running a component, it calls SC_SECRET_<NAME_UPPER> from the environment:

sc.secret(...) call Environment variable read
sc.secret("ssh_pub_key") SC_SECRET_SSH_PUB_KEY
sc.secret("stripe_api_key") SC_SECRET_STRIPE_API_KEY
sc.secret("db_password") SC_SECRET_DB_PASSWORD

The rule: dots and lowercase letters become _ and uppercase.

Exporting secrets

Export secrets in your shell before running any sc command:

export SC_SECRET_SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
export SC_SECRET_STRIPE_API_KEY="sk_live_..."

In CI (GitHub Actions example):

- name: Deploy
  env:
    SC_SECRET_STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }}
  run: uv run sc build --env production

Error if missing

If a required secret is not set, the engine raises a clear error before running any command:

Secret 'stripe_api_key' not found: set environment variable SC_SECRET_STRIPE_API_KEY

Dry-run mode

In dry-run mode (--dry-run), secrets are not read from the environment. A safe placeholder string is substituted instead, so you can render templates and inspect planned commands without needing real secrets:

sc plan --dry-run   # SC_SECRET_* not required
sc build --dry-run

--secrets-in-plaintext

By default, even in verbose mode (-v), secret values are masked in logs. If you need to see the actual resolved value (e.g. to debug a template), pass --secrets-in-plaintext:

sc build -v --secrets-in-plaintext

Warning

Never use --secrets-in-plaintext in CI logs that are stored or shared.

HttpTest and proxies

HttpTest uses trust_env=False by default, which means it ignores HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY environment variables. This is intentional: smoke tests hit infrastructure IPs directly, and proxy variables (often set for secrets managers or corporate networks) frequently cause timeouts to raw public IPs while the same URL loads fine in a browser.

If you genuinely need the test to route through a proxy:

HttpTest(
    name="api health",
    url="http://10.0.0.5:8000",
    trust_env=True,   # honour HTTP_PROXY
)