Share `.env` files as an encrypted `lazysecrets://share/…` link. The files are encrypted with a secret's value, so anyone who can read that secret can open the link. **Sharing:** `S` → `f` on a repo (all its plain env files), an env file, or a key in one (its file). - **The key** is `share.key` from the repo's `.lazysecrets.yaml`, else from the config. It can be a `lazysecrets://` link, a Key Vault URL or an `@Microsoft.KeyVault(...)` reference. - **Without `share.key`,** a picker built on Go to opens, titled "Share .env", with "Pick a secret to encrypt with" in its own border. It lists only secrets, leaving out values from plain `.env` files. Pasting a reference picks it. Picking shares at once, and the picker stays open until the link is copied. If the secret can't be used, the reason shows in red in the picker: it can't be read, or it doesn't meet `share.keyRules` (which rule failed is named). `esc` cancels. - **`share.keyRules`** (defaults `minLength: 32`, `minClasses: 2`; never under 16) applies when sharing, not when opening. - **On Azure,** the link pins the key's version, so rotating the key doesn't break old links, and disabling a version revokes them. - **The command line:** `lazysecrets share [--key <secret>] <env files>`. **Opening** works by paste, `ctrl+o`, the clipboard offer, the link handler or `lazysecrets <link>`. 1. It first says which repo the link is from, how many files it holds and which key it uses, and decrypts only after `o`. 2. It saves into the repo's clone, found by its remote, showing which files are new, which would replace one there, and which git doesn't ignore. 3. Without a clone, it asks for a folder and saves straight away. The prompt stays open, with the reason in red, until the files are written. 4. If decryption fails, a popup says why: the first line of the reason, `r` for the whole message, `g` to go to the key's secret. A key that has changed is named by where it lives: a Databricks or SOPS value changed in place, an Azure current version that isn't the one the link was made with, or a pinned version, meaning the link may be damaged. **Format** (`internal/share`): a version byte, then a JSON header with the key, the repo and the file count, then an age file (scrypt 2^15, with the key's value as passphrase) holding the files as deflated JSON, all as unpadded base64url. Links are capped at 16 KB. A future format gets a new version, and old ones stay readable. **Safety:** - A link can only write env files, inside the folder: never in `.git`, never through a symlink. - New files are created with mode 0600. - Opening accepts an scrypt work factor of at most 2^20, and unpacks at most 1 MB. **Along the way:** - Opening a link to a secret ends on its details, as `enter` would. - `o` on an Azure secret opens its portal page, and in the versions view, that version's page. - The details pane follows its secret's list when it reloads in the background. Before, it kept what it showed first, including an old portal address. - `ref.Read` is shared by `get` and sharing, with Azure `VersionedValue` for pinning. - `provider.Contents` lets the demo repos share their env files. `--demo` has a share key (`kv-shared-prod / env-share`), so the whole flow works there. - New dependency: `filippo.io/age`. Tested end to end in the TUI and the demo, the CLI, and the `share` package. In a real vault: version pinning, opening into a clone, and revocation by disabling the version. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #54
8.1 KiB
Keys
? lists every key with what it does, the focused pane's first; type to
filter, enter runs one. The help bar at the bottom shows the most useful
keys for where you are. Every key can be rebound.
The rule: a letter in the lists, ctrl+ that letter where you type a filter
(f stars, ctrl+f stars while filtering).
Moving around
| Key | Action |
|---|---|
j/k, ↑/↓ |
move |
g/G |
top / bottom |
tab, shift+tab/h |
next / previous pane |
l |
the details of what's selected, on the right (h goes back) |
1–4 |
jump to pane |
enter / esc, ⌫ |
drill in / back (also clears a filter or leaves the versions view) |
[ / ] |
previous / next tab of the focused pane: Sources and Favourites in Sources; Secrets, Keys, Certs in Secrets |
/ |
filter the focused list by name or note (how it matches); enter keeps it, esc clears it. While typing: ctrl+j/ctrl+k move, ctrl+y copies, ctrl+r reveals, ctrl+f stars |
` |
switch the Sources pane between grouped by provider and a flat list; enter/space on a provider folds it |
r |
refresh the focused pane |
q, ctrl+c |
quit |
Searching
/ in a pane, Go to, ? and other popups with a text field all search
the same way, with fzf's scoring (the
same as snacks.nvim's picker): letters at the start of a word or in one
run count far more than letters scattered through a name, matches in an
item's own name more than in its path or note, and equally good matches
put the shorter name first.
| Query | Finds |
|---|---|
dbpw |
fuzzy: db-password |
pass prod |
both terms, in any order |
smtp | key |
either |
'prod |
exactly prod, not fuzzy |
^kv- / -dev$ |
names starting / ending with it |
!test |
without test |
Lowercase ignores case; typing an uppercase letter makes that term match case exactly.
Secrets
| Key | Action |
|---|---|
space |
reveal / hide the selected value (public material for keys and certificates) |
y |
copy the value without revealing it; cleared from the clipboard after 30s. On an Azure account's row: its object ID; in its pane, the selected field |
Y |
copy the reference (@Microsoft.KeyVault(...), key/certificate URL, {{secrets/scope/key}}) |
v |
versions of the selected item (Azure); space/y/Y then act on that version; esc, ⌫ or v to go back |
o |
open the selected item in the browser (over SSH: copy the link) |
e |
open the selected SOPS or .env file, or a secret's file at its line (how) |
s / S |
copy a link to the selected item / share menu (also env files, encrypted) |
ctrl+o |
open a link or reference (or just paste one) |
x |
custom commands |
L |
sign in again (shown when a login has expired) |
U |
a newer lazysecrets: its changelog, and update in place (restart to use it); or look for one |
A revealed value is shown as it reads best: JSON indented, and PEM
certificates as their subject, issuer, dates, names and thumbprint, with
any other PEM block (a private key) named but not shown. y still copies
it exactly as stored.
A revealed value hides again after revealTimeout (60s) and when the
terminal loses focus (hideOnBlur); see config.
Stars and notes
| Key | Action |
|---|---|
f |
star the selected source, vault or secret: it gets a ★ and sorts first in its list |
n |
write a short note on it, shown dimmed on its row and in the detail pane |
A star belongs to the account you starred the item under; a note shows under every account. Both are kept in the state file.
Go to
ctrl+s opens Go to on its Search tab, F on Favourites (everything you
starred) and R on Recent (what you used last). enter goes to the
selected item.
Search has the scope on the left and what's in it on the right. The
scopes are All, then grouped like the Sources pane: each account (or
Databricks, or Repos) with its sources under it, with ○ ◐ ● for how
much of each is loaded. Repos searches every repo without asking Azure
or Databricks for anything. Go to opens on All; ctrl+s again narrows
it to the source or group selected in the Sources pane, and once more
goes back to All. Typing a search loads what it covers: everything on
All, else the account or source picked; results appear as lists
arrive. That's once each time Go to opens, and only what isn't loaded
yet; ctrl+a loads again, lists that failed included.
Like a pane, Go to is either browsing or typing a filter:
| Browsing | Typing | Action |
|---|---|---|
j/k |
ctrl+j/ctrl+k |
move |
g/G |
top / bottom | |
ctrl+s |
ctrl+s |
only the source or group you're in / All |
h/l, tab |
ctrl+h/ctrl+l, tab |
scope list / results |
[ / ] |
previous / next tab | |
f |
ctrl+f |
star |
r |
ctrl+r |
load the selected item, or the scope when nothing is selected |
a |
ctrl+a |
load everything in the scope (again) |
/ |
esc |
start typing / clear it and go back to browsing |
esc, q |
close |
Favourites and Recent come from the state file, so they work before anything loads.
Layout
The pane on the right describes what's selected in the pane you're in: the
account or subscription in Sources, the vault in Vaults, the secret in
Secrets. Going into it (l, or 4) keeps it on that; there j/k,
/ and y work on its rows, and h goes back. A value you reveal stays in view whichever pane you're in, until
it's hidden.
On top, the status pane (0) shows the version, a newer release and how
your accounts are doing; e there opens your config in your
editor, as in lazygit. Focused, the right pane lists more under the
logo (when there's room): the version and updates (U), each account
(L on one that needs it signs in), what's expiring (enter goes to
it), this session's errors, newest first (what a pane showed, or the
footer flashed before you moved on; not kept after quitting), the config,
state and cache files (e opens one in your editor), and links to the
docs, source, issues, releases and changelog (o opens one; on the
version or update, its release), then the changelog of every release up
to yours, built in so it needs no network: / filters it (/fixed,
/search). y copies any row.
| Key | Action |
|---|---|
ctrl+←/ctrl+→ or </> |
move the divider between the left panes and the detail pane |
ctrl+↓/ctrl+↑ or }/{ |
make the focused left pane taller / shorter |
+ / _ |
zoom the focused pane: normal → half → full screen, and back |
= |
reset the layout (divider, heights, zoom) |
The divider and pane heights are remembered (zoom isn't). macOS uses
ctrl+arrows for Mission Control and switching desktops by default, hence
the < > { } alternatives.
Rebinding keys
Every action can be rebound in the config, per context:
keybinding:
lists: # the panes, when not typing
star: [x] # replaces f
versions: [] # unbound
filter: # typing a filter in a pane
star: [ctrl+x]
popup: # popups with a text field: help, notes, open link, Go to while typing
down: [ctrl+j, down]
menu: # popups without a text field
search: # Go to's own actions while typing (on top of popup)
goto: # Go to while browsing
An action you set gets exactly the keys you list, replacing its defaults;
[] unbinds it. Actions you don't set keep their defaults, also across
layered config files. lazysecrets keybindings prints every action with
its keys (your config applied), ready to copy and edit. A key bound to two
actions that apply together is an error at startup, naming both. The help
bar, ? and every hint show the keys you bound. Fixed: the letters inside
menus (they're part of each entry), and ctrl+c, which always quits.
Without the kitty keyboard protocol (or tmux extended-keys), some
combinations never reach a terminal app, such as ctrl+shift+x, ctrl+1
or ctrl+enter.