Guides
Secrets with 1Password
Name a secret in a project's environment instead of holding it, and let each box read it when needed.
An env value in .berth/config.json, a
kit or a box's own config can name a secret instead of
holding it, so the file, or the kit, can be shared, even publicly, without
one in it:
{
"env": {
"DATABASE_PASSWORD": "op://dev/cal-db/password",
"STRIPE_SECRET_KEY": "op://dev/Stripe test/secret key",
"OPENAI_API_KEY": "env://OPENAI_API_KEY"
}
}References
op://vault/item/field(orop://vault/item/section/field, with?attribute=otpand the like) is 1Password's own reference syntax, read with the 1Password CLI on the box:op read.env://NAMEpasses on a variable from berthd's own environment, under whatever name the project wants.
Setting up 1Password on a box
- Install
opon the box. berthd finds it on itsPATH, in~/.local/bin,/opt/homebrew/binor/usr/local/bin, or wherever$BERTH_OPsays. - Sign it in. With a
service account,
set
OP_SERVICE_ACCOUNT_TOKENin berthd's own environment or in the box's~/.berth/env.json(which every worktree also gets, so berthd's environment is the tighter place). Otherwise berthd uses the box user's own signed-inop. - Check a reference:
berth secret test devl op://dev/cal-db/password # Resolved op://dev/cal-db/password: 24 charactersOr from the app: Project settings → Environment → Test. Either way the box reports only whether it could read it and how long the value is.
How values are handled
The box reads a reference when it builds a worktree's environment for a
hook, a flow, a setup script or exec, and keeps the value in memory for
five minutes. It never writes a value to disk or puts one in a log, an
event, the API or an error: config, GET /v1/locations/{name}/config and
GET /v1/env show the reference. A value is not expanded, so a $ in a
password stays a $.
Terminals, agents and services don't get values from berthd at all: tmux
takes a session's environment as command-line arguments, which other
processes can read, and a service's unit file is on disk and restarted by
the service manager without berthd. So they get the references, and their
program runs behind berthd secret exec, which resolves them in its own
memory and then replaces itself with the shell or agent. It prints which
variables it could not set, and reports to the box which resolved and which
failed (never a value), so the box can announce failures. For a service,
env:// reads the service manager's environment. Each start reads op
afresh, so a service that keeps crashing reads it on every restart.
When a reference fails
If a reference cannot be read (no op, not signed in, no such item, a read
that takes over 15 seconds), what needs it still starts, without that
variable, and the box sends a secret.failed event with the variable, the
reference and the reason, which the app shows as a notification. A failure
is remembered for 30 seconds, so a broken reference does not run op for
every hook. When it reads again, the box sends secret.resolved.
A kit that uses op:// should list { "tool": "op" } in requires.