Secrets
Secrets deliver sensitive values — passwords, tokens, private keys — through provider references and runtime injection. Workflow and compiled definitions store references rather than resolved values; runtime evidence follows the narrower redaction contract described below.
This page explains the conceptual model. For configuration details, see the Secrets reference. For security controls, see Secrets security.
Provider references
A secret entry maps an environment variable name to a provider URI:
deploy:
secrets:
DATABASE_PASSWORD:
ref: keepass://local/main#services/loom/deploy:password
This secrets entry stores the reference, not the password. Keep credential values out of other workflow fields, including scripts and variables. 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 keeps resolved values out of workflow source. Runtime evidence still requires inspection and sanitization before you share receipts, logs, or declared artifacts.
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) |
| Static definitions | Value remains visible | Provider reference only |
| Textual run evidence | Value may be visible | Exact secret matches are redacted in the outputs listed below |
| Declared artifacts | Contents are unchanged | Contents are unchanged and are not scanned |
| 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 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 resolve only the secrets declared on the current job and return values to the injection flow. Missing or invalid credentials fail the job for required secrets. Loom omits unresolved required: false secrets from injection and continues.
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
Loom redacts exact matches to resolved secret values before writing to these supported text outputs:
- Console and event streams
- Receipt stdout/stderr
- Error fields containing command output
- Provider lifecycle messages
Redacted values appear as [REDACTED:SECRET_<NAME>].
Host and Docker stdout/stderr are processed as continuous byte streams before newline and 8 KiB framing, so an exact configured value remains matchable when transport chunks split it. Redaction does not detect transformed or encoded values, and it does not scan raw declared artifact contents.
Avoid printing secret-bearing environment variables, and inspect and sanitize evidence before sharing it. Redaction does not cover transformed values or raw artifacts.
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, Graph IR, and compiled workflow output contain provider references rather than resolved values.
- 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.- Exact secret matches are redacted from the supported text outputs; transformed or encoded values and raw declared artifacts remain outside that boundary.
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.