Commit Graph
24 Commits
Author SHA1 Message Date
kebandClaude Opus 5.5 18918db1d4 refactor: no group list in an account's details, and no Microsoft Graph call for it
CI / Checks (pull_request) Successful in 22s
PR title / Conventional title (pull_request) Successful in 1s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 14:23:14 +02:00
keb b64ca81dfe Merge branch 'feat/expiring' into feat/l-for-details
CI / Checks (pull_request) Successful in 25s
PR title / Conventional title (pull_request) Successful in 2s
# Conflicts:
#	docs/azure.md
#	internal/ui/app/app_test.go
2026-10-11 13:56:22 +02:00
kebandClaude Opus 5.5 c9bc4c1431 feat: what's expiring, in the status pane and lazysecrets expiring
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:55:52 +02:00
kebandClaude Opus 5.5 8e8d1c5af0 fix: the merged tests' closing braces
CI / Checks (pull_request) Successful in 24s
PR title / Conventional title (pull_request) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:53:22 +02:00
keb 75f62240fc Merge remote-tracking branch 'origin/feat/container-details' into feat/l-for-details
CI / Checks (pull_request) Failing after 5s
PR title / Conventional title (pull_request) Successful in 2s
# Conflicts:
#	internal/ui/app/app_test.go
2026-10-11 13:51:22 +02:00
keb dee144f33f Merge remote-tracking branch 'origin/feat/first-run' into feat/l-for-details 2026-10-11 13:50:46 +02:00
keb 1d7efb135d Merge remote-tracking branch 'origin/feat/cache-age' into feat/l-for-details 2026-10-11 13:50:46 +02:00
kebandClaude Opus 5.5 365cb5b1df feat: l goes to the details of what's selected; enter still drills in
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:50:43 +02:00
kebandClaude Opus 5.5 cd35a8acf4 fix: details load once the cursor rests, and moving on cancels them
CI / Checks (pull_request) Successful in 25s
PR title / Conventional title (pull_request) Successful in 1s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:43:38 +02:00
kebandClaude Opus 5.5 879b961ac5 feat: a vault's settings come with the vault list, with no requests of their own
CI / Checks (pull_request) Successful in 24s
PR title / Conventional title (pull_request) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:42:48 +02:00
kebandClaude Opus 5.5 5381cf5d43 feat: vaults, scopes and files show their details: a vault's settings, who has a scope, a file's keys and git status
CI / Checks (pull_request) Successful in 24s
PR title / Conventional title (pull_request) Successful in 1s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:41:12 +02:00
kebandClaude Opus 5.5 164d933bea feat: with nothing to show, the right pane says how to get started
CI / Checks (pull_request) Successful in 23s
PR title / Conventional title (pull_request) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:37:21 +02:00
kebandClaude Opus 5.5 4d6db97d54 feat: a list from the cache says how old it is while it reloads
PR title / Conventional title (pull_request) Successful in 2s
CI / Checks (pull_request) Successful in 24s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 13:35:11 +02:00
keb 9b0329e9da feat: the changelog in the status pane, built in (#12)
The status pane's rows (`0`, then `enter`) end with the changelog: every release up to the running one, newest first.

```
v0.2.0     2026-10-12
           added: Search with fzf's scoring and query syntax (#11) (65dc2d7)
           fixed: …
v0.1.0     2026-10-10
           Hello world 👋
```

- `CHANGELOG.md` is embedded at build time by a small root package (`changelog.go`, `package lazysecrets`, `//go:embed`), so it needs no network and matches the binary. `release.sh` updates the file before tagging, so a release's binary includes its own entry. `go install …@latest` gets it too, since the module includes the file.
- Entries show as text: links become `(#11) (65dc2d7)` (`update.PlainLinks`, shared with the `U` notes). `/` filters them like any Fields pane (`/fixed`, `/search`), and `y` copies one.
- `cliff.toml`: #11 was squash-merged with #10 (the status pane) in it, so a preprocessor rewrites its entry to name both. Otherwise the status pane would be missing from the changelog.

Test for the parsing: versions and dates, kinds, links as text, a release's own words, and the header and footer left out.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #12
2026-10-11 13:12:51 +02:00
keb 56d3d25c9c feat: link each changelog entry to its PR and commit (#11)
Like Immich's and RomM's release notes: every changelog entry now links to its pull request and its commit, in `CHANGELOG.md` and in the release notes on Gitea:

```
- Search with fzf's scoring and query syntax ([#11](…/pulls/11)) ([65dc2d7](…/commit/65dc2d7…))
```

- `cliff.toml`: the entry template adds the short commit hash as a link; a postprocessor turns the squash commit's `(#N)` into a link to the PR.
- The app shows release notes as text (`U`, and the status pane's changelog to come), so `Release.Notes()` turns Markdown links back into their text: `Search (#11) (65dc2d7)`.

Checked with `git cliff --unreleased` on main: every entry since v0.1.0 gets both links. Test for the link stripping.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #11
2026-10-11 11:20:19 +02:00
keb 1c8d69d957 feat: the right pane describes what's selected in the pane you're in (#9)
The right pane kept showing the selected secret when you moved to Vaults or Sources. Now it follows focus:

| focus | right pane |
|---|---|
| Sources | the account (group row), or the subscription / workspace / repo: name, note, ID / profile / path, host or remote, account, web page, vault count |
| Vaults | the vault / scope / file: name, note, URI / backend / format, source, web page, counts of loaded secrets, keys, certificates |
| Secrets | the secret, as before |
| the right pane itself | what it described when you went in; `shift+tab` goes back there |

All but the secret use the `Fields` pane (#7), so `j`/`k`, `/` and `y` work on them; `Detail` loses the error message it got in #4, which is now a red "problem" row in `Fields`. A value revealed from a left pane stays in view until hidden, so `space` from any pane still shows it. `tab` from a subscription goes to Vaults as before; only an account row skips to its details.

This also changes the startup view: focus starts in Sources, so the right pane describes the first subscription instead of the first secret (golden output updated). Tests that read the secret pane focus Secrets first; a new test walks secret → vault → subscription → into the pane → back, and reveals from Sources.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #9
2026-10-11 10:59:40 +02:00
keb c8abc1dc95 feat: the value's keys on the line below it: reveal and copy (#8) 2026-10-11 10:38:00 +02:00
keb 71396f1e02 feat: a Fields pane for anything but a secret, first for Azure accounts: fields and groups to move through, filter and copy (#7) 2026-10-11 10:37:40 +02:00
keb f6c4f5f6f6 fix: show search instead of grouped/flat in the Sources help bar (#6)
The Sources pane's help bar listed `` ` `` (grouped/flat sources), a rarely used toggle, but not Go to (`ctrl+s`), the main way to find things. Search now takes its place, right after `enter`; the toggle is still in `?`.

Golden output updated: at 100 columns the bar now reads `enter open • ctrl+s search • s copy link • S share… • f star • F favourites • … • ? help • q quit` (`n note` moves behind the `…`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #6
2026-10-11 10:09:46 +02:00
keb 52b6257dd5 feat: show who an Azure account signs in as, in Details on its row (#5)
On an Azure account's group row, the Details pane now describes the account:

| field | from |
|---|---|
| name | token `name` |
| user (and "service principal") | az's account list |
| tenant: name · ID | az's account list (the name is borrowed from another entry in the same tenant when az left it out) |
| object ID | token `oid`; `y` on the row copies it |
| sign-in: MFA or not, and how | token `amr` |
| directory roles | token `wids`: built-in roles by name, others as `role 1a2b3c4d`, the default member role left out |
| subs: count · default | az's account list |
| cloud | az's account list, when not AzureCloud |

Nothing is fetched for it: the claims are the ones from the token lazysecrets already gets for the account's own tenant, read without verification. The token itself is never stored or shown. Before the first token, only the az-list fields show. A failing account shows its sign-in problem there instead (from #4).

New optional `provider.Accounts` interface; `azure.Provider` implements it. Tests: the fields from claims and az's list, sign-in methods, the UI showing it on the group row only, and `y` copying the object ID. Checked against a real signed-in account (name, MFA · password, default subscription) and an expired one (az-list fields only, since there's no token).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #5
2026-10-11 10:09:17 +02:00
keb a82f6bff27 fix: say a sign-in error once, then in Details for that account (#4)
A failing account's error ("sign-in required … press L to run az login --tenant …") stayed in the footer for the whole session.

- **Footer:** it's now an ordinary message, shown once when an account's error first appears (at start, or when a load fails), and gone on the next key press. It's said again only when the errors change, or for another account.
- **Details:** with that account's group header or one of its sources selected, the Details pane shows the error and the sign-in hint, in place of "Select a vault or scope…".
- **`L`** signs in to the selected account when it needs it, else to the last one that asked, as before. With two accounts, `L` used to run whichever sign-in had failed most recently.

Test: two accounts, one failing to list its subscriptions. The message is in the footer at start and gone after a key press, in Details on that account's group, and `L` targets it. It isn't shown on the other account's rows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #4
2026-10-11 10:06:28 +02:00
keb 10dc747f0f feat: keep what was loaded between runs, and start where you left off (#2)
Starting lazysecrets again now shows what you had loaded at once, and puts you back where you were.

- **Cache file** `~/.cache/lazysecrets/cache.json` (0600, written atomically): the Sources lists, vaults/scopes, secrets' metadata, Describe results and each list's cursor. **Never values**, and never repos (they're on disk anyway). Loaded on start; lists older than 2 minutes reload in the background as before. Saved every 30s when changed, and on quit.
- **Housekeeping:** entries not loaded for 30 days are dropped, as is everything from accounts no longer signed in (every cache key starts with the account ID). The file has a format version; another version is ignored and replaced. `cache: false` turns it off; `--demo` never uses it.
- **Sources are cached too:** Azure lists subscriptions over the network, so without this the Sources pane would still wait.
- **Go to** searches everything cached straight away, and its background loading now also refreshes lists from an earlier run instead of skipping them.
- **Where you left off:** the state file remembers the selected source, vault or secret per folder (the `--dir` or working directory, 100 most recent folders), and the next start in that folder goes back there quietly (no error if it's gone). Starting on a link skips it.

Docs: `cache:` in config.md, a Cache section, the place in State, and the README Privacy section now mentions the cache file.

Tests: cache round trip with a backend too slow to answer (lists and cursor come from the file), no value in the file, file mode 0600, old and signed-out entries dropped, back where it was left, not for another folder or a link.

This touches `app.go` near PR #1's changes (Model fields, the Update switch), so whichever merges second needs a small conflict fix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #2
2026-10-11 09:53:32 +02:00
keb 17d2705e12 feat: e opens a repo's SOPS or .env file, in nvim, sops edit or your editor (#1)
`e` on a file in a repo opens it; on a secret, it opens the file at that key's line.

- **SOPS files**: `sops edit` in the terminal, then back to lazysecrets with the keys reloaded. Exit 200 (nothing changed) shows "unchanged".
- **Other files inside nvim** (`$NVIM` set): lazysecrets asks that nvim, over `--remote-expr`, to open the file once lazysecrets' terminal closes, then quits. The file lands in the window you came from, not the closing float. Started from a shell in a terminal, it opens in the previous window straight away. No change to the nvim plugin is needed.
- **Otherwise**: `$VISUAL`/`$EDITOR` in the terminal (with `+N`, `file:N` or `-g file:N` for editors that take a line), else the system default app.

The repo provider now records each key's line (YAML node lines, env/ini line numbers) behind a new optional `provider.Files` interface. Other providers show "only SOPS and .env files in repos can be opened".

The nvim handoff was tested against a headless nvim 0.12: a floating terminal closed on exit the way snacks does, and a shell in a split. A file name with a space and a quote opened at the right line in both. Unit tests cover lines per format, the nvim, sops and default-app paths, and the editor line arguments.

Note: `e` is a new default key, so a config that already binds `e` to something else now gets the "bound to both" error, until one of them is rebound.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
Reviewed-on: #1
2026-10-11 09:34:05 +02:00
kebandClaude Opus 5.5 6fab41703e Hello world 👋
Release / Build and publish (push) Successful in 22s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 23:58:25 +02:00