Writes a .env carrying the same list .monkeys does: every secret's key on a
line of its own, and every public value as it already stands. A key with
nothing after it sets nothing, so the file satisfies whatever wanted one while
the secrets keep arriving through run.
monkeys poo
wrote /tmp/monkeys-jn4u9q/.env for @test: 2 keys, 1 value
It lands in /tmp unless you say otherwise, so nothing appears in a project
that did not ask for it. The header names the profile when the project declares
more than one, since that is the profile run has to be given to match.
A placeholder would be worse than nothing. The three things that read a .env
treat a bare key and a KEY=x differently, and only the bare key is safe in
all three:
what reads it
DATABASE_URL
DATABASE_URL=x
dotenv, so Vite, SvelteKit, Next
ignored, the environment's value stands
ignored, the environment's value stands
Docker Compose env_file:
taken from the host environment
x goes into the container
set -a; . .env
the environment's value survives
overwritten with x
The bottom two rows are the reason. A placeholder reaches a container or a
shell as a real value, so the program starts and fails later, at the first
call that uses the key, where the cause is no longer obvious.
IMPORTANT
If you maintain a framework, please make its loader read .monkeys, taking
each key's value from the operating system's vault. Have it replace .env,
or sit between .env and the process environment.
--path names the directory to write into, and the file inside it is always
.env:
monkeys poo --path .
a .env into ~/code/shop/.env, where a commit can take it. go ahead? [y/N] ywrote ~/code/shop/.env for @test: 2 keys, 1 value
Anywhere inside a git checkout it asks first, because that is where a commit
can find the file. Answer anything but y and nothing is written. --open
shows whatever it wrote in the file manager, wherever that was.
A .env that poo did not write is left alone:
monkeys: ~/code/shop/.env was not written by poo: monkeys eat it first, or move it aside
A tool that wants the values, not only the keys, takes them as vault lookups:
monkeys poo @production --WITH_SECRETS
wrote /tmp/monkeys-QA6tuw/.env for @production: 3 lookups, 1 value
# monkeys' poo @production, vault lookups. read https://monk3ys.dev/pooDATABASE_URL="$(security find-generic-password -s monkeys -a shop.production/DATABASE_URL -w)"STRIPE_SECRET_KEY="$(security find-generic-password -s monkeys -a shop.production/STRIPE_SECRET_KEY -w)"SENTRY_DSN="$(security find-generic-password -s monkeys -a shop.production/SENTRY_DSN -w)"PORT=8080
That is the line export writes, so nothing of the secret is on disk and the
file is as safe to keep as the keys were. The profile has to be named: the
lookup carries one profile's stored name, and the wrong one resolves to the
wrong secret rather than to nothing.
This is the one command that writes secrets, in the open, to a file. Nothing
else in monkeys does. Reach for it only when the tool cannot run a lookup,
and delete what it wrote when you are done.
A reader that parses the file without running anything gets the text of the
lookup instead of the secret. Vite, SvelteKit, Next and Compose all read a
.env this way:
vite got: "$(security find-generic-password -s monkeys -a shop.production/DATABASE_URL -w)"
Only then is there reason to put the secrets themselves in a file, which is
what this flag does. It runs the lookups and writes what they return:
wrote /tmp/monkeys-01mjsu/.env for @production: 3 secrets, 1 valuethe secrets are in the open in that file; delete it when the deploy is done
# monkeys' poo @production, secrets in the open. delete this file. read https://monk3ys.dev/pooDATABASE_URL="postgres://user:pa\$\$w0rd@host/shop"STRIPE_SECRET_KEY="sk-demo-live"SENTRY_DSN="https://[email protected]/1"PORT=8080
It is a fallback for the place that takes no vault and no command, such as a
deploy dashboard that wants the variables pasted in. That is a person's errand,
so the flag wants a terminal and refuses a pipe:
monkeys: --EXPAND_DANGEROUSLY leaves secrets in a file for a person to paste, so it needs a terminal
--path still works, and inside a git checkout the question is no longer one
letter:
plain secrets into ~/code/shop/.env, where a commit can take them. not recommended. [UNDERSTOOD/N] UNDERSTOOD
A $ inside a secret is written \$, which both a shell and dotenv read back
as one character, so a password like pa$$w0rd arrives whole. A secret holding
a quote or a backslash is refused instead, since no dotenv line carries those
back unchanged.
A profile names which list to write, the way it does everywhere else:
monkeys poo @production
One file is written, never one per profile. Which profile a program runs under
is run's to decide, and a second place to decide it is a second place to get
it wrong.