feat: lazysecrets list prints everything lazysecrets can find, for fzf and editor pickers (#70)
`lazysecrets list` prints every source, vault and secret lazysecrets can find, one per line, for fzf, editor pickers and scripts: what Go to searches, without the TUI. What's cached prints at once; what's missing or older than `--max-age` loads in the background and streams in. It stops when the reader goes (a pick in fzf), saving what it loaded. - Text: kind, mark (✗/⚠, ★, ◷ and the provider icon), name, status (why it couldn't be read, or expired / expires in 12d), note, account and link, tab-separated; kind first and account and link last, so new fields go between. Coloured from the theme; `--color never`, `--icons=false`, `--stars=false`, `--recent`, `--notes=false`, `--expiry=false`. - `--format json`: an object per line, with starred, recent, lastUsed and uses, expires, enabled, note, reference and url too. - `--kind` lists only some kinds, and doesn't load lists only other kinds need; `--cached` loads nothing. - `lazysecrets open --action go|copy|show` skips the "what to do" menu and ends in the list, like Go to; `open` and `get` take `--account`, the account list printed, rather than asking which. - The cache file moved to `internal/cachefile`: saves merge with the file under a lock, so list and the TUI don't undo each other. - `ui.recentIcon` marks items used lately with ◷ in the TUI's lists too; Recent now means the last 90 days. - --demo has stars, notes, recent use, and expired, expiring and disabled secrets. - docs/integration.md documents get, list and an fzf picker; docs/links.md is docs/sharing.md. Reviewed-on: #70 Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
This commit was merged in pull request #70.
This commit is contained in:
1 parent
dbb0eb2bbd
commit
39454d47a8
45 files changed
+2107
-222
No files matched your search
+182
@@ -0,0 +1,182 @@
|
||||
# Sharing
|
||||
|
||||
Subscriptions, workspaces, vaults, scopes, repos, files and secrets are
|
||||
shared as a `lazysecrets://` link, in chat or a ticket. Whoever opens
|
||||
it lands on that item, reading it with their own account and
|
||||
permissions: the link names the item, never its value. Env files can
|
||||
also be [shared encrypted](#sharing-env-files), in the link itself.
|
||||
|
||||
```
|
||||
lazysecrets://azure/kv-app-prod.vault.azure.net vault
|
||||
lazysecrets://azure/kv-app-prod.vault.azure.net/keys vault, Keys tab
|
||||
lazysecrets://azure/kv-app-prod.vault.azure.net/secrets/db-password secret
|
||||
lazysecrets://azure/kv-app-prod.vault.azure.net/secrets/db-password/91d3e0 one version
|
||||
lazysecrets://databricks/adb-1111111111111111.11.azuredatabricks.net/app/storage-key
|
||||
lazysecrets://repo/git.example.com%2Fteam%2Finfra/secrets%2Fapp.yaml/db.password
|
||||
```
|
||||
|
||||
## Sharing a link
|
||||
|
||||
`s` copies a link to the selected item (from the versions view, pinned to
|
||||
that version). `S` opens the share menu:
|
||||
|
||||
- secrets: the link (`o`), the plain Key Vault URL (`u`), the config
|
||||
reference (`y`) or the web page (`b`); in an env file, also the file as
|
||||
an [encrypted link](#sharing-env-files) (`f`)
|
||||
- vaults and scopes: a link (`o`), a link that opens on the current tab
|
||||
(`t`), the plain vault URL (`u`) or the web page (`b`)
|
||||
- subscriptions and workspaces: a link (`o`) or the web page (`b`)
|
||||
- repos and env files: also their env files as an
|
||||
[encrypted link](#sharing-env-files) (`f`)
|
||||
|
||||
## Sharing env files
|
||||
|
||||
`.env` files usually live only on your machine. `S` → `f` shares them as
|
||||
an encrypted link, on a repo (all its plain env files), an env file, or a
|
||||
key in one (its file):
|
||||
|
||||
```
|
||||
lazysecrets://share/AQ…
|
||||
```
|
||||
|
||||
The files are encrypted with a secret's value, so whoever can read that
|
||||
secret (in Key Vault, Databricks or a repo's SOPS file) can open the link,
|
||||
and nobody else: who may open it is up to the vault's access, as for
|
||||
everything else. Make a secret for it once, random:
|
||||
|
||||
```sh
|
||||
az keyvault secret set --vault-name kv-team --name env-share --value "$(openssl rand -base64 32)"
|
||||
```
|
||||
|
||||
and name it in the repo's `.lazysecrets.yaml` (committed: the whole team
|
||||
uses it) or your config (for repos that don't name one), by its
|
||||
`lazysecrets://` link, Key Vault URL or `@Microsoft.KeyVault(...)`
|
||||
reference:
|
||||
|
||||
```yaml
|
||||
sharing:
|
||||
key: https://kv-team.vault.azure.net/secrets/env-share
|
||||
```
|
||||
|
||||
With neither, sharing asks which secret, in [Go to](keys.md#go-to): it
|
||||
lists only secrets, and `enter` picks one (pasting a reference picks it
|
||||
too).
|
||||
|
||||
Anyone with a link can try to guess the key, so sharing refuses one that
|
||||
isn't long and varied enough, saying how (never showing it). By default
|
||||
that's 32 characters of two kinds; your config can ask for more, or less:
|
||||
|
||||
```yaml
|
||||
sharing:
|
||||
keyRules:
|
||||
minLength: 32 # characters; 16 at least
|
||||
minClasses: 2 # kinds of character: lowercase, uppercase, digits, symbols
|
||||
```
|
||||
|
||||
Opening a link doesn't check them.
|
||||
|
||||
On the command line, `lazysecrets share [--key <secret>] <env file>...`
|
||||
prints the link.
|
||||
|
||||
Opening a share link says which repo it's from, how many files and which
|
||||
secret it's encrypted with, and decrypts only when asked: lazysecrets
|
||||
reads the secret with your access, then shows where each file goes in
|
||||
your clone of the repo (or asks for a folder, if it isn't here), which
|
||||
ones would replace a file there and which ones git doesn't ignore. It
|
||||
saves them all, only the new ones, or none. New files are readable by you
|
||||
only.
|
||||
|
||||
A link holds the files' paths and contents encrypted ([age](https://age-encryption.org),
|
||||
the secret's value as passphrase); the repo, the secret and the number of
|
||||
files are in the clear. Links stay under 16 KB, which fits chat and
|
||||
tickets.
|
||||
|
||||
A link stays readable as long as its secret is. On Azure it's pinned to
|
||||
the secret's version, so adding a new version (rotating) doesn't break
|
||||
old links, and disabling the old version, or taking away someone's
|
||||
access, shuts them out; Databricks secrets have no versions, so changing
|
||||
the value breaks every old link. Whoever has read the secret's value
|
||||
before can decrypt links made with it without asking the vault, so rotate
|
||||
it now and then: new links use the newest version.
|
||||
|
||||
## Opening a link
|
||||
|
||||
- Paste it into lazysecrets, or press `ctrl+o`, which reads the clipboard
|
||||
and fills in any reference it finds there. Key Vault URLs,
|
||||
`@Microsoft.KeyVault(...)` and `{{secrets/scope/key}}` work too.
|
||||
- `lazysecrets <link>` (or `lazysecrets open <link>`) in a terminal.
|
||||
- Click it anywhere, once the [link handler](#from-the-browser-and-chat) is
|
||||
set up.
|
||||
|
||||
If you copy a `lazysecrets://` link elsewhere and switch back, lazysecrets
|
||||
offers to open it, once per link. It looks at the clipboard at startup,
|
||||
when the terminal regains focus (in tmux: `set -g focus-events on`) and,
|
||||
for terminals that don't report focus, on a key press at most every 3
|
||||
seconds. It keeps nothing but `lazysecrets://` links, doesn't offer a link
|
||||
to what's already selected (like one you just copied with `s`), and can't
|
||||
read the clipboard over SSH.
|
||||
|
||||
lazysecrets finds the vault in your accounts (one Resource Graph query per
|
||||
account) and jumps to it, asking which account to use when several can see
|
||||
it, ending on a secret's details as `enter` on it would. Links say what,
|
||||
not what to do: opening a link to a secret asks whether to just go to it,
|
||||
also copy or show its value, or (`y`) copy its value without going there.
|
||||
`lazysecrets open --action go|copy|show <link>` does one without asking
|
||||
and ends in the list, like Go to,
|
||||
and `--account <account>` picks the account (as [`list`](integration.md#listing-for-fzf-and-pickers)
|
||||
prints it) when several can see it.
|
||||
|
||||
## From the browser and chat
|
||||
|
||||
```sh
|
||||
lazysecrets handler install # run it in the terminal links should open in
|
||||
lazysecrets handler uninstall
|
||||
```
|
||||
|
||||
Use an installed binary (`go run`'s is temporary). lazysecrets offers to do
|
||||
this at startup when links don't open it (or open a lazysecrets that no
|
||||
longer exists): set it up, not now, or don't ask again, which is
|
||||
remembered in the state file. `linkHandler.prompt: false` in the config
|
||||
turns the question off too.
|
||||
|
||||
`handler install` registers `lazysecrets://` with the system: clicking a
|
||||
link then opens a new window of the terminal you ran it in, with
|
||||
lazysecrets on that link. It recognises kitty, Ghostty, WezTerm, iTerm2,
|
||||
Terminal.app, Alacritty, GNOME Terminal, Konsole and foot, also inside
|
||||
tmux; `--terminal NAME` picks another. It records your `PATH` and config
|
||||
locations, since apps start without your shell's environment (and so
|
||||
without `az`): run it again after moving lazysecrets or changing those.
|
||||
|
||||
- macOS: a small background app, `~/Applications/Lazysecrets Links.app`
|
||||
- Linux: a desktop entry claiming `x-scheme-handler/lazysecrets`, set as
|
||||
the default with `xdg-mime` (desktops following freedesktop.org)
|
||||
- Windows: not yet
|
||||
|
||||
The config can override the terminal, or run any other:
|
||||
|
||||
```yaml
|
||||
linkHandler:
|
||||
terminal: ghostty # instead of the one install detected
|
||||
command: [foot, --title, secrets, "{cmd}"] # any terminal; {cmd} is the lazysecrets command
|
||||
reuse: true # hand links to a running lazysecrets first
|
||||
prompt: true # offer to set up the handler at startup
|
||||
```
|
||||
|
||||
### Where a clicked link opens
|
||||
|
||||
- **In a terminal** (a link in a terminal app): a lazysecrets that
|
||||
terminal shows (or whose tmux session one of its tmux clients can switch
|
||||
to) gets it, never one elsewhere; otherwise a new window opens.
|
||||
- **Anywhere else** (Slack, a browser): the lazysecrets you used last (key
|
||||
press or focus), preferring one already on screen; a tmux client is
|
||||
switched to its session if needed, its terminal comes to the front, and
|
||||
a hidden dropdown terminal (kitty's quick access terminal) is shown.
|
||||
With none running, a new window opens.
|
||||
|
||||
The link is then offered as if pasted. `linkHandler.reuse: false` always
|
||||
opens a new window.
|
||||
|
||||
Running instances listen on a socket in `$XDG_RUNTIME_DIR/lazysecrets`, or
|
||||
`run/` in the state directory, readable only by you. A link from a web page
|
||||
can only make lazysecrets go somewhere: it asks before copying or showing
|
||||
anything.
|
||||
Reference in new issue
Block a user