Encrypted values
Generated Markdown for references/concept_encrypted_values.md.
Open book page Back to the skill graph
# Encrypted values
_secret("…") — password-encrypted values stored in playbook.wcl, encrypted in place by the CLI and decrypted at run time._
A value that must not sit in git in the clear is written as `secret("…")`. It is a
WCL builtin, so it works anywhere an expression does — a `vars` entry, a step's
`properties`, a gather's `params`, a `condition`:
\`\`\`wcl
vars {
db_password = secret("hunter2")
}
\`\`\`
`config-weave secrets encrypt` rewrites each call **in place**, replacing the
literal with a `CWENC1` blob (Argon2id key derivation into XChaCha20-Poly1305).
Only the call text changes — comments, indentation and everything else in the file
are left byte-for-byte alone.
\`\`\`wcl
vars {
db_password = secret("CWENC1.a1B2….Zx….Qm…")
}
\`\`\`
`check`, `apply` and `test` take the password from `$CONFIG_WEAVE_PASSWORD`,
`--password-stdin` or `--password-file PATH` and decrypt as the value is needed.
There is no prompt: a missing password is exit 2, so an automated run fails loudly
instead of blocking on a terminal that isn't there. A playbook with no `secret()`
calls never asks for one.
> [!WARNING]
> **An un-encrypted secret fails validation**
> `secret("plaintext")` is a hard error from `check`, `apply`, `validate`, `test` and `docs` — you cannot run, or commit, a playbook whose secrets were never encrypted. The message names `config-weave secrets encrypt` as the fix.
> [!NOTE]
> **One password per playbook**
> Adding a new secret requires the password that already unlocks the file: `secrets encrypt` decrypts every existing value before it writes anything. Use `config-weave secrets rekey` to change the password — it re-encrypts every value under a fresh salt.
> [!WARNING]
> **Playbook-only**
> `secret()` in a `package.wcl` is a validation error. Packages are shared and distributed via git, so a package cannot hold a value encrypted under one playbook's password — which also rules it out of `test` and `scenario` blocks.
> [!NOTE]
> **Decrypted values are scrubbed from output**
> Every plaintext this run decrypts is masked to `***` in diagnostics, the NDJSON log, step messages and script `log::*`/`print` output — so a resource that echoes its own password parameter does not leak it. Generated docs show `secret(…)` and never the blob.
## Related
- [Variables](../references/concept_variables.md)
- [Playbook](../references/concept_playbook.md)
- [playbook.wcl](../references/entity_playbook_wcl.md)
[← Back to SKILL.md](../SKILL.md)