Encrypt Secrets from an Existing .env¶
dotenv-fusion migrate secret selects secrets from a basic .env, writes their public references to .env-fuse, and stores their values in an age-encrypted bundle. It moves values into encrypted storage; it does not move inline contract definitions into a schema.
For that separate operation, see dotenv-fusion migrate schema.
Secret values stay inside the local process and are sent to age through stdin; they are never printed or written to a plaintext temporary file.
Review the selection¶
Use repeatable, case-sensitive globs. Always quote them for the shell:
dotenv-fusion migrate secret \
--from .env \
--to .env-fuse \
--secret '*_TOKEN' \
--secret '*_PWD' \
--secret 'DATABASE_PASSWORD' \
--public 'PUBLIC_*' \
--age-output secrets/application.env.age \
--dry-run
--public excludes matching names after secret selection. Every --secret pattern must match at least one variable, which catches misspelled patterns. Dry-run prints only selected names, preserved names, and output paths. It does not require a recipient and writes nothing.
Encrypt and write¶
Encryption needs public recipients, not decryption identities:
dotenv-fusion migrate secret \
--from .env \
--to .env-fuse \
--secret '*_TOKEN' \
--secret '*_PWD' \
--public 'PUBLIC_*' \
--age-output secrets/application.env.age \
--age-recipient 'age1...'
Recipients are repeatable. Recipient files are also supported:
dotenv-fusion migrate secret \
--secret '*_TOKEN' \
--age-output secrets/application.env.age \
--age-recipients-file config/age-recipients.txt
By default, the age store is the parent of --age-output, so the example emits references such as:
Use --age-store DIR when the ciphertext should be nested under a larger runtime store. The age output must remain below that store.
Safety contract¶
- The source must be a basic
.env; directives and duplicate assignments are rejected. - The original source is never overwritten or deleted.
- Non-secret lines and ordinary comments are retained.
- Selected values are resolved with dotenv-fusion's normal quote and expansion rules before encryption.
- Plaintext is held only in memory and passed to
agevia stdin. - New
.env-fuseand ciphertext outputs use mode0600on POSIX. - Existing outputs are refused.
--forcereplaces only the exact targets; existing.env-fusepermissions are preserved and ciphertext becomes0600. - Output and errors contain names and paths, never values.
When --age-output is beneath secrets/ beside the generated .env-fuse, the runtime store needs no configuration. Configure only the decryption identity:
export DOTENV_FUSION_AGE_IDENTITY=/home/user/.config/age/keys.txt
dotenv-fusion check -f .env-fuse
dotenv-fusion exec -f .env-fuse -- application
For another layout, set DOTENV_FUSION_AGE_STORE in .env-fuse or in the parent environment. Relative paths are based on the generated file's directory.
AI agent skill¶
The repository includes the skills/dotenv-fusion-migrate AI agent skill in SKILL.md format. It guides an agent through dry-run review and validation while explicitly forbidding direct reads of .env, identities, plaintext bundles, and ciphertexts. The deterministic CLI remains the only value-handling component.