Commands · reference

config-weave secrets

5 min read · 2026-09-02 · config-weave 0.1.0

secrets encrypts, decrypts and re-keys the secret("…") values in playbook.wcl, in place. An author writes secret("plaintext") anywhere an expression is legal, runs secrets encrypt, and the call's argument is replaced with an encrypted blob. Everything else in the file, including comments and formatting, is untouched: the command rewrites only the byte span of each call. The subcommands work on the raw source, so they are never blocked by the validation error that an unencrypted secret() raises. See Variables and secrets for the model and Encrypt secrets in a playbook for the workflow.

Synopsis

console
config-weave secrets <COMMAND>

Commands:
  encrypt  Encrypt every plaintext secret("…") in place
  decrypt  Rewrite encrypted values back to plaintext so they can be edited
  rekey    Change the password: re-encrypt every value under a new one

Passwords

The current password comes from exactly one of three sources: --password-stdin, --password-file PATH or $CONFIG_WEAVE_PASSWORD. These are global options and the same ones check, apply and test use. Giving more than one is an error. Giving none when the command needs one is an error. There is no interactive prompt, so an unattended run fails with exit code 2 rather than waiting. One trailing newline is stripped from stdin and file input, and an empty password is rejected. The new password for rekey comes from --new-password-file PATH or $CONFIG_WEAVE_NEW_PASSWORD; stdin is not offered for it because stdin may already be carrying the old one.

The encrypted form

An encrypted value is a CWENC1 blob: the prefix CWENC1. followed by three URL-safe base64 fields separated by dots, a 16-byte salt, a 24-byte nonce, and the ciphertext with its authentication tag. The key is derived from the password with Argon2id, and the value is sealed with XChaCha20-Poly1305. Every secret in one file shares one salt, so a run derives the key once. A wrong password and a tampered blob are indistinguishable, and both are reported as a wrong password.

playbook.wclwcl
vars {
  db_password = secret("CWENC1.<salt>.<nonce>.<ciphertext>")
}

secrets encrypt

console
config-weave secrets encrypt [PLAYBOOK_DIR]

Encrypts every plaintext secret() call in place. When the file already holds encrypted values, the password is first proven against them, so a new secret can only be added by someone who can read the existing ones, and the new blobs reuse the existing salt. When there are no encrypted values yet, a fresh salt is generated. A file with no secret() calls reports that and needs no password. A file whose secrets are all encrypted reports that the password was verified and changes nothing.

ArgumentMeaning
PLAYBOOK_DIRThe playbook directory. Default ..

secrets decrypt

console
config-weave secrets decrypt [PLAYBOOK_DIR]

Rewrites every encrypted value back to secret("plaintext") so it can be edited. Calls that are already plaintext are left alone. The real values are then in the clear on disk, and the playbook fails validation until they are encrypted again, so run encrypt before committing.

ArgumentMeaning
PLAYBOOK_DIRThe playbook directory. Default ..

secrets rekey

console
config-weave secrets rekey [--new-password-file <PATH>] [PLAYBOOK_DIR]

Changes the password. Every encrypted value is decrypted with the current password and re-encrypted under the new one with a fresh salt. Any secret() call that is still plaintext is encrypted in the same pass.

Argument or optionValueMeaning
PLAYBOOK_DIRThe playbook directory. Default ..
--new-password-filePATHRead the new password from a file. The alternative is $CONFIG_WEAVE_NEW_PASSWORD. Exactly one must be given.

Examples

Encrypt the secrets in the current playbook with the password in the environment.

console
CONFIG_WEAVE_PASSWORD='hunter2' config-weave secrets encrypt
playbook.wcl: encrypted 2 secret(s)

Edit a secret: decrypt, change the value, encrypt again.

console
config-weave secrets decrypt ./my-playbook --password-file ~/.weave-pw
playbook.wcl: decrypted 2 secret(s) — they are now in the clear on disk
$EDITOR ./my-playbook/playbook.wcl
config-weave secrets encrypt ./my-playbook --password-file ~/.weave-pw

Rotate the password, reading the old one from stdin and the new one from a file.

console
echo "$OLD" | config-weave secrets rekey ./my-playbook --password-stdin --new-password-file ./new-pw

Exit status

0 when the file was rewritten or there was nothing to do. 2 when the password was missing, given twice or wrong, when the new password for rekey was missing, when a blob is malformed, when playbook.wcl could not be parsed or written, or when the directory holds no playbook.wcl.