EP001 · EnvFolio 1.0
Keep Your Secrets Out of Plain Sight
EnvFolio keeps your texts and secrets in one store, and hands them to a command only when you ask. Version 1.0 is out.
Quick question: where are your application secrets right now? In a .env file. In an export line in your ~/.bashrc. In your shell history, from the day you
pasted a token into a curl. Plain text, in all of those, on every machine you work
on.
And they travel. You work in containers, in cloud dev environments, next to AI agents that read every file in the project. Plain-text secrets go wherever your files go.
Meet EnvFolio
EnvFolio is a small command-line tool, folio, that keeps your texts and your secrets in one store. It hands them to a program directly, as environment variables,
and only when you ask. That is the whole idea:
folio execonly when you askNot on a command line. Not in a file. Not on the screen.
With 1.0, its commands, options and file formats (the store, vars files, exports and backups) are stable: a change that breaks any of them will come with a new major version.
Built on pass
EnvFolio does not invent its own vault. It is built on pass, the standard Unix password
manager. Your secrets are encrypted with your own GPG key, and every change goes into the
store's git history. The store lives in ~/.folio, apart from your own ~/.password-store, but it has the same layout, so plain pass still opens
every secret in it:
PASSWORD_STORE_DIR=~/.folio pass show gh/token Texts and secrets
EnvFolio stores two kinds of items. A text, like a user name or a host,
is kept plain, and signed with your key, so you can tell if someone changed it. A secret is encrypted, as it should be. The two never blur: every command
that touches a secret says secret out loud, and a secret is never taken as an argument.
folio text insert -t "demo@example.com" gh/user
folio secret insert gh/token folio ls shows both, side by side:
Hand them to a command
To use the items, run your command through folio exec. Each item becomes an
environment variable for that one command, named after its path: / becomes _, then it is uppercased. So gh/token becomes GH_TOKEN. Want another name? Put it in front: GITHUB_TOKEN=gh/token.
Texts load by default; secrets come along only with -s (--secrets).
Every item is checked and read before the command starts. If one fails, the command does not
run. The echo below is only there to prove the value arrived; a real command just uses
it.
Name a folder, and every item under it comes along. Not sure what you will get? Add --names: it shows which variable gets which item, and stops. Nothing is read or
decrypted, and the command does not run.
Need the items for a whole session instead of one command? folio shell does the same,
but starts your shell. It prints the names it loaded, never their values.
Write it down once: vars files
Typing item names gets old. For a project, write down once what its command needs, and where each value comes from, in a vars file:
GH_TOKEN=@{gh/token}
DB_URL=pg://@{db/user}:@{db/pass}@${DB_HOST}/app
LOG_LEVEL=info@{name} | a text or secret from the store |
${NAME} | from your environment |
…:-fallback | if unset or missing: @{gh/token:-none} |
@{folder/*} | every item under a folder |
LOG_LEVEL=info | a constant |
The file holds where the values are, not the values, so commit it with the code. Nothing in it
ever runs: EnvFolio reads it a character at a time and never hands it to a shell, so $(…) and backticks are refused. folio vars check checks the file
without a store, in CI for example. Then one line runs the project's command. Here, deploy.sh is a stand-in that reports what it got without showing a secret:
Take it anywhere
Now the part that started it all: running that command on a machine that has no store, like a
remote server: a CI/CD server, say. folio export packs just the items your vars
file names into one encrypted file. It makes a new key for this export only, so your store's key
never leaves your machine, and it always locks the file: with a passphrase you choose, or with --to, to the public key of the machine it is going to.
On the other side, folio exec --from runs the command with the items from that file.
No store is needed, and none is made. The file is unpacked into a private temporary folder, and that
folder is removed before the command starts: nothing is left behind.
So what may travel in the open? The vars file holds no secret, and the export file is locked:
both can sit next to the code, or on the server. What opens the file is the one thing to keep to
yourself: the passphrase, kept out of the repository and never next to the file; or, with --to, the secret key on the machine it is going to, which never travels at all. Your secrets get to
a machine you do not own, without its provider ever touching them.
Why trust it
EnvFolio is one bash script, and it runs on the bash 3.2 that macOS ships. It needs little more
than pass, gpg and git. You can read every line, and see
for yourself that no secret goes where it shouldn't.
folio backup saves the whole store, its key included (still under its passphrase),
into one file, and folio restore brings it back on a new machine. And if you ever
stop using EnvFolio, nothing is locked in: your secrets are plain pass entries, and your
texts are plain files.
Get it
Download folio from the latest release, and check it
against SHA256SUMS. It is the script that sees your secrets, so mind its
permissions: anyone who can change it can read them. Make it executable but writable by you
only, and put it on your PATH in a folder that only you can write to:
sha256sum -c SHA256SUMS # shasum -a 256 -c SHA256SUMS on macOS
chmod 755 folio # everyone may run it, only you may change it
mkdir -p ~/.local/bin && mv folio ~/.local/bin/
folio version Or with Homebrew, which checks the download against its checksum and installs it for you:
brew install nawaman/tap/folio Then folio init makes your store, in a folder only you can get into (700), and folio help lists the rest. For Tab completion, add eval "$(folio completion bash)" to your ~/.bashrc, or the zsh one to your ~/.zshrc.
Bottom line
Your secrets don't belong in .env files, shell profiles or history. Put them in one pass store, write down once what each project needs, and let folio exec hand the values to the command that needs them, and to nothing else. When the work moves to another
machine, an encrypted export goes with it, and leaves nothing behind.
Keep your secrets out of plain sight.
Links
- EnvFolio on GitHub
- The latest release
- The manual: every command, with examples
pass, the standard Unix password manager