Secrets
Secrets deliver sensitive values — passwords, tokens, private keys — to jobs at runtime without exposing those values in workflow YAML, compiled artifacts, receipts, or logs.
This page explains the conceptual model. For configuration details, see the Secrets reference. For security controls, see Secrets security.
The core idea: references, not values
A secret entry maps an environment variable name to a provider URI:
deploy:
secrets:
DATABASE_PASSWORD:
ref: keepass://local/main#services/loom/deploy:password
The workflow never contains the password — only the reference. Loom resolves the reference through the named provider at execution time and injects the value into the job environment. After the job finishes, the resolved value is discarded.
This separation means you can commit workflow files, share receipts, and review logs without risk of credential exposure.
How secrets differ from variables
Variables hold non-sensitive configuration. Their values are visible in compiled workflows, receipts, and logs. Secrets hold sensitive values by reference only.
| Aspect | Variables | Secrets |
|---|---|---|
| Stored in YAML | Plain value | Provider reference URI (ref) |
| Visible in artifacts | Yes (compile output, receipts, logs) | Never — redacted at all output boundaries |
| Scope | default, job, or workflow level | Job-only (default.secrets is invalid) |
| Default injection | Direct environment value | Temp file path (file: true) |
| Key collision | Allowed across scopes (merges) | Same key in both variables and secrets is rejected |
Use secrets when the value would cause damage if leaked — credentials, API keys, signing keys, connection strings. Use variables for everything else.
Provider-backed resolution
Each ref URI starts with a scheme that identifies the provider:
| Scheme | Provider | Source |
|---|---|---|
env:// | Environment passthrough | Host process environment variable |
keepass:// | KeePass | Local encrypted .kdbx database |
op:// | 1Password | Vault via Go SDK (service account token) |
Providers are pluggable. All providers follow the same contract: resolve only the secrets declared on the current job, return values only to the in-memory injection flow, and fail closed when credentials are missing or invalid.
See Secrets providers for provider-specific setup.
File-first injection
By default (file: true), Loom writes the resolved secret to a temporary file with 0600 permissions and sets the environment variable to the file path. Scripts read the value with cat "$VAR_NAME".
This default reduces accidental leakage from shell tracing (set -x), ps output, and command-line interpolation. Set file: false only when a tool requires a direct environment value.
For Docker jobs, file-injected secrets are bind-mounted read-only into the container and rewritten to container-local paths.
Automatic redaction
Resolved secret values are redacted before Loom writes to any output boundary:
- Console and event streams
- Receipt stdout/stderr
- Error fields containing command output
- Provider lifecycle messages
Redacted values appear as [REDACTED:SECRET_<NAME>].
Redaction is a safety net, not a substitute for discipline. Avoid printing secret-bearing environment variables in scripts even though redaction exists.
Job-scoped declaration
Secrets are valid only on individual job blocks. default.secrets is intentionally invalid — this prevents broad fan-out of sensitive material across all jobs in a workflow.
A secret name cannot appear in both variables and secrets for the same job. The schema validator rejects this overlap to eliminate ambiguity about whether a value is sensitive.
Secret spec fields
| Field | Required | Default | Description |
|---|---|---|---|
ref | Yes | — | Provider URI (env://..., keepass://..., op://...) |
file | No | true | true: inject as temp-file path. false: inject raw value in env var. |
required | No | true | true: fail job if unresolved. false: silently omit and continue. |
Key safety invariants
- Workflow YAML contains references only — never credential material.
- Vault credentials (master passwords, keyfiles, service account tokens) are supplied through runtime environment configuration, not through workflows.
CI_DEBUG_TRACE=truecombined with anyfile: falsesecret hard-fails withSECRETS_UNSAFE_DEBUG_TRACE.- Secret bytes never appear in Graph IR, compiled workflows, receipts, or log artifacts.
Next steps
- Secrets reference — injection modes, error codes, and configuration details.
- Secrets security — threat model, controls, and operational guardrails.
- Secrets providers — provider-specific setup, URI formats, and runtime requirements.