Secrets
Sensitive values like database passwords and API keys have no place in config files. noorm provides encrypted secret storage that travels with your project, unlocks with your identity, and injects into templates at runtime.
What Secrets Are
Secrets are encrypted key-value pairs stored in your local state file (.noorm/state/state.enc). They never touch disk in plain text.
Secrets are for sensitive values that get inserted into your database via SQL templates—not for database connection credentials. Common uses:
- API keys stored in configuration tables
- Encryption keys for sensitive data columns
- Service credentials (AWS, Stripe, SendGrid)
- OAuth client secrets
Secrets integrate directly with SQL templates, so you can reference them without exposing values in your source code or version control.
Setting a Secret
Local secret values are managed through the TUI so that passwords never touch shell history or ps listings:
noorm uiFrom there, press s for Settings → Secrets. The secret form masks password input, validates connection strings as URIs, and stores the result encrypted in .noorm/state/state.enc. The same screen lists the secrets for the active config — showing which are set, which are missing, and their declared types. Values stay hidden.
For CI/CD pipelines that need to push secrets non-interactively, use the vault — it stores encrypted team secrets directly in the database and is fully scriptable (noorm vault set KEY "value").
Config-Scoped vs Global Secrets
Secrets come in two scopes:
| Scope | Use Case | Example |
|---|---|---|
| Config-scoped | Per-environment credentials | Database password for prod |
| Global | Shared across all configs | Third-party API key |
Config-scoped secrets belong to a single config. When you delete the config, its secrets go with it.
Global secrets persist independently and are available everywhere.
In templates, access them differently:
-- Config-scoped secret
CREATE USER readonly WITH PASSWORD '{%~ $.secrets.DB_PASSWORD %}';
-- Global secret
-- Using API key: {%~ $.globalSecrets.SHARED_API_KEY %}See Templates for full syntax reference.
Using Secrets in Templates
Secrets inject into SQL templates via the $ context object:
-- sql/users/create-readonly.sql.tmpl
CREATE USER {%~ $.secrets.READONLY_USER %}
WITH PASSWORD '{%~ $.secrets.READONLY_PASSWORD %}';
GRANT SELECT ON ALL TABLES TO {%~ $.secrets.READONLY_USER %};If a template references a missing secret, it fails at runtime. Define your required secrets upfront to catch this early.
Secret Requirements in Settings
You can require secrets at two levels: universally (all configs) or per-stage (specific environments).
Universal Secrets
Define in the root secrets section of settings.yml:
# .noorm/settings.yml
secrets:
- key: ENCRYPTION_KEY
type: password
description: App-wide encryption keyEvery config requires these secrets, regardless of stage.
Stage Secrets
Define within a stage to require secrets only for matching configs:
# .noorm/settings.yml
stages:
prod:
description: Production database
secrets:
- key: DB_PASSWORD
type: password
description: Main database password
required: true
staging:
secrets:
- key: DB_PASSWORD
type: password
- key: DEBUG_KEY
type: stringA config named prod requires its stage secrets plus universal secrets. A config named dev requires only universal secrets (plus any dev-stage secrets).
Secret Types
The type field controls input behavior:
| Type | Input Behavior |
|---|---|
string | Plain text |
password | Masked, no echo |
api_key | Masked, no echo |
connection_string | Plain text, URI validation |
Types are hints for the CLI. All secrets are stored identically (encrypted strings).
Secrets in CI/CD
The local secret store exists for per-developer overrides — it's deliberately TUI-only so that raw values never leak into shell history. For non-interactive environments, push values to the vault instead, which is scriptable end-to-end:
# Write a secret to the vault
noorm vault set DB_PASSWORD "$DB_PASSWORD"
# Pipe a secret to avoid process listings
echo "$DB_PASSWORD" | noorm vault set DB_PASSWORD
# List vault secrets as JSON
noorm --json vault list
# Remove a vault secret
noorm vault rm OLD_API_KEYVault secrets sit below local secrets in the resolution hierarchy, so a developer can still override a vault value locally through noorm ui without affecting anyone else.
Security Notes
noorm takes several measures to protect your secrets:
- Encryption at rest - Secrets are stored in
.noorm/state/state.encusing AES-256-GCM encryption - Key derivation - The encryption key derives from your private identity key via HKDF
- Values never displayed - The CLI shows secret keys only, never values
- Masked input - Password-type secrets use non-echoing input
- No logging - Secret values are never emitted to observer events
- Automatic redaction - The logger masks secret fields if they appear in event data
Don't Commit state.enc
Add .noorm/state/state.enc to your .gitignore. The file is encrypted with machine-specific keys and won't work on other machines.
Deleting Secrets
Remove optional local secrets through the TUI: noorm ui → Settings → Secrets → highlight the entry and press d. For team-shared values stored in the vault, use noorm vault rm <KEY>.
Required secrets (those declared in settings.yml) cannot be deleted, only updated. The TUI tells you whether a secret is universal or stage-specific when you try to delete a required one.
