diff --git a/README.md b/README.md index 1f04d24..b2e26ef 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,12 @@ A terminal UI for finding, reading and sharing secrets. Inspired by the fantasti CLI, `sops`, `git`). No config file needed. - **Search everything**: `ctrl+s` searches every source at once, with fzf-style matching. -- **Share links**: Share `lazysecrets://` links with colleagues. A colleague opens it - with their own access, from the terminal or with a click in the browser - or chat. `.env` files can be shared too, as a link encrypted with a - secret your team can read. +- **Share links**: Share `lazysecrets://` links with colleagues. - **Neovim integration**: via [lazysecrets.nvim](https://github.com/karleinarb/lazysecrets.nvim) - **Careful with values**: values stay hidden until you reveal them, and copied values are cleared from the clipboard after 30 seconds. - **Scriptable**: `lazysecrets get ` prints a value for scripts and - pipes, and `lazysecrets list` everything it can find, for fzf and editor - pickers ([integration](docs/integration.md)). + pipes. - **Favourites**: star the secrets you use most for easy access. - **Expiry warnings**: secrets, keys and certificates that expire soon are marked, listed together in the status pane. @@ -81,21 +77,37 @@ use most: | `?` | every key, searchable | | `q` | quit | + +## Integration +Lazysecret let you integrate it into your workflows by `lazysecrets` `list`/`get`/`open` + +Here is an example of implementing a picker in `fzf`: +```sh +lazysecrets list | fzf --ansi --delimiter='\t' --with-nth='2..-3' --nth='2..' --accept-nth=-1 \ + --header 'enter: link · ctrl-o: open · ctrl-y: copy value · ctrl-x: copy and close' \ + --bind 'ctrl-o:become(lazysecrets open --action go --account {-2} {-1})' \ + --bind 'ctrl-y:execute-silent(lazysecrets get --account {-2} {-1} | pbcopy)+change-header(Copied the value of {3})' \ + --bind 'ctrl-x:become(lazysecrets get --account {-2} {-1} | pbcopy)' +``` + +![fzf-example](docs/assets/fzf-example.png) + +More defails in the [Integration](docs/integration.md) docs + ## Docs - [Keys](docs/keys.md): every key, Go to, the layout, and rebinding keys - [Azure Key Vault](docs/azure.md): accounts, permissions, pinned vaults - [Databricks](docs/databricks.md): profiles and Key Vault-backed scopes - [SOPS and .env files](docs/repos.md): which repos and files, decrypting -- [Links](docs/links.md): sharing, opening, and opening links from the - browser and chat -- [Integration](docs/integration.md): `lazysecrets get` in scripts, and - `lazysecrets list` for fzf and editor pickers +- [Sharing](docs/sharing.md): links to secrets, encrypted env files, and + opening links, also from the browser and chat +- [Integration](docs/integration.md): how lazysecrets can integrate into other systems - [Custom commands](docs/custom-commands.md): run your own commands on a secret - [Config](docs/config.md): every option, themes, layered configs, the state file -- [Development](docs/development.md): building, tests, how changes land and +- [Development](docs/development.md): building, tests, pull requests and releasing ## Privacy diff --git a/docs/assets/fzf-example.png b/docs/assets/fzf-example.png new file mode 100644 index 0000000..2f616ff Binary files /dev/null and b/docs/assets/fzf-example.png differ diff --git a/docs/assets/lazysecrets.png b/docs/assets/lazysecrets.png index 22ee0bd..03aa90c 100644 Binary files a/docs/assets/lazysecrets.png and b/docs/assets/lazysecrets.png differ diff --git a/docs/integration.md b/docs/integration.md index 2a5c207..8e3098f 100644 --- a/docs/integration.md +++ b/docs/integration.md @@ -2,7 +2,7 @@ lazysecrets works outside its own window too: `lazysecrets get` reads a value for scripts, and `lazysecrets list` lists everything for fzf, editor -pickers and your own tools. Both take the [links](links.md) lazysecrets +pickers and your own tools. Both take the [links](sharing.md) lazysecrets copies and shares. For Neovim, there's [lazysecrets.nvim](https://github.com/karleinarb/lazysecrets.nvim). @@ -19,7 +19,8 @@ It reads the value directly, with your az accounts (the one that last read it first), the Databricks profile for the workspace, or sops in your clone of the repo; a version in the link reads that version. `--account` tries that account first, as [`list`](#listing-for-fzf-and-pickers) prints it. -The value ends with a newline only on a terminal. +The value ends with a newline only on a terminal. When it can't read the +value, it says why on stderr and exits with status 1. ## Listing, for fzf and pickers @@ -29,69 +30,65 @@ tab-separated: | Field | | |---|---| | kind | `source`, `vault`, `secret`, `key` or `certificate` | +| mark | ✗ when something's wrong (expired, or couldn't be read) or ⚠ when it expires soon; ★ when starred; ◷ when used lately (with `--recent`); and the provider's icon | | name | `platform-prod / kv-app-prod / db-password` | +| status | why a vault or source couldn't be read, or that it has `expired` or `expires in 12d` (within `ui.expiryWarningDays`), or empty | +| note | your note on it (`n` in lazysecrets), after a note icon (✎ without icons), or empty | | account | what it's listed through: an az account (`Azure:/`), `Databricks` or `Repos` | | link | its `lazysecrets://` link | -It's what Go to searches, so fzf, or an editor's picker, can search it -instead, showing the names and acting on the links: +What's cached prints at once, then what loads follows as it arrives: read +it as a stream. Values are never listed. It stops quietly when the reader +goes, like fzf after a pick. Kind stays the first field, and account and +link the last two; new fields only ever go between. The mark has a field of +its own so a search can leave it out: in fzf, `--nth` searches the name, +so `^prod` finds names starting with prod. +| Flag | | +|---|---| +| `--format json` | an object per line instead, for editor plugins (below) | +| `--kind secret,vault` | only these kinds: `source`, `vault`, `secret`, `key`, `certificate`; lists only other kinds need aren't loaded | +| `--cached` | only what's cached, at once: nothing is loaded from Azure or Databricks | +| `--max-age 2m` | load cached lists older than this again | +| `--errors=false` | leave out the vaults and sources it couldn't read | +| `--color never` | no colours, for scripts | +| `--icons=false` | no provider icons | +| `--stars=false` | no ★ before starred names (in `favouriteColor`) | +| `--notes=false` | no note icon before a note | +| `--recent` | ◷ before names used lately, in `mutedColor`; default `ui.recentIcon` | +| `--expiry=false` | no expiry: not in the status, and no ✗ or ⚠ for it | + +With `--format json`, each line is an object with these fields; new ones +may be added: + +| Field | | +|---|---| +| `link`, `kind`, `account` | as above | +| `error` | why it couldn't be read, only then | +| `provider` | `azure`, `databricks` or `repo` | +| `path` | the names: `["platform-prod", "kv-app-prod", "db-password"]` | +| `accountLabel` | the account's short name, when several az accounts are signed in | +| `starred` | starred for this account | +| `note` | your note on it, if any | +| `reference` | how config refers to a secret: `@Microsoft.KeyVault(SecretUri=…)` or `{{secrets/scope/key}}` (`Y` in lazysecrets) | +| `url` | its web page, in the Azure portal or the Databricks workspace (`o` in lazysecrets) | +| `recent` | used lately, as Recent (`R`) lists: in the last 90 days, among the 100 used last | +| `lastUsed`, `uses` | when it was last used, and how often; only when `recent`, to sort by | +| `expires` | when a secret, key or certificate expires, if it does (Azure) | +| `enabled` | `false` for a disabled one; only where the provider says (Azure) | + +`lazysecrets open --action go --account ` opens one in +lazysecrets without asking what to do or which account, ending in the +secrets list, like Go to. + + +### Example usage with fzf ```sh -lazysecrets list | fzf --ansi --with-nth='2..-3' --accept-nth=-1 \ +lazysecrets list | fzf --ansi --delimiter='\t' --with-nth='2..-3' --nth='2..' --accept-nth=-1 \ --header 'enter: link · ctrl-o: open · ctrl-y: copy value · ctrl-x: copy and close' \ --bind 'ctrl-o:become(lazysecrets open --action go --account {-2} {-1})' \ - --bind 'ctrl-y:execute-silent(lazysecrets get --account {-2} {-1} | pbcopy)+change-header(Copied the value of {2..-3})' \ + --bind 'ctrl-y:execute-silent(lazysecrets get --account {-2} {-1} | pbcopy)+change-header(Copied the value of {3})' \ --bind 'ctrl-x:become(lazysecrets get --account {-2} {-1} | pbcopy)' ``` +![fzf-example](assets/fzf-example.png) -`--with-nth='2..-3'` shows and searches only the names; `{-1}` and -`--accept-nth=-1` are the link, `{-2}` the account. All but the name are -one word, so this works without `--delimiter`. To filter by kind -yourself: `awk -F'\t' '$1 == "secret"'`. - -`enter` prints the link (`lazysecrets get $(…)`), `ctrl-o` opens it in -lazysecrets, `ctrl-y` copies the value, saying so in the header, and -`ctrl-x` copies it and closes fzf (`pbcopy` on macOS; `wl-copy` or `xclip` -on Linux). A value copied this way isn't cleared from the -clipboard after `values.clipboardClear`, as one copied in lazysecrets is. - -`--account` makes `open` and `get` use the account it was listed through, -when several of yours can see it: without, `open` asks which, and `get` -tries the one that last read it first. The link stays as it is, to copy -and share; the account isn't part of it. `--action` tells `open` what to -do rather than asking, as it does for a link clicked elsewhere: `go` to -it, `copy` its value too, or `show` it. It ends in the secrets list, like -Go to, rather than on the details as a clicked link does. - -What's [cached](config.md#cache) prints at once. Then, like Go to, it loads -what's missing or older than `--max-age` (2m), and what's new in it follows -as it arrives: fzf shows it while you type. `--cached` loads nothing from -Azure or Databricks, for an answer at once. Repos are always read, from -disk. What it loads is cached for the TUI too. It stops when the reader -goes, after a pick in fzf. - -`--kind` lists only some kinds, comma-separated: `source`, `vault` (also -Databricks scopes and repo files), `secret`, `key`, `certificate`. Lists -only other kinds need aren't loaded: `--kind source,vault` asks for no -secrets. Keys and certificates load only when asked for this way; else, -like Go to, they're listed as far as you opened them in lazysecrets. - -A vault or source it can't read is a line too, as it fails: its name, -then `✗` and why in red (`errorColor`), with its link, so opening it -shows more. They're in the list, not on stderr, which would draw over fzf. -`--errors=false` leaves them out. - -The name is coloured from your [theme](config.md#theme), with the -provider's icon when [icons](config.md#theme) are on (`ui.icons`); fzf -shows the colours with `--ansi`. `--color never` leaves them out, for -scripts, and `--icons=false` the icons. The link is never coloured. - -`--format json` prints an object per line instead, for editor plugins, -without colours or icons, and with `error` on a list it couldn't read: - -```json -{"link":"lazysecrets://azure/kv-app-prod.vault.azure.net/secrets/db-password","kind":"secret","provider":"azure","path":["platform-prod","kv-app-prod","db-password"],"account":"Azure:alice@example.com/","accountLabel":"alice"} -``` - -`accountLabel`, the account's short name, is there when several az -accounts are signed in. Values are never listed.