feat: pick the share key in Go to, or by reference
CI / Checks (pull_request) Successful in 38s
PR title / Conventional title (pull_request) Successful in 1s

Sharing without share.key opens Go to as a picker of secrets instead
of asking for a link: it lists only secrets, enter picks one, and a
pasted reference picks it too. The key, there and in share.key or
--key, can be a secret's lazysecrets:// link, Key Vault URL or
@Microsoft.KeyVault(...) reference.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kebandClaude Opus 5.5 committed 2026-10-13 12:09:08 +02:00
1 parent 4d57c19772
commit bc691d786a
13 files changed
+152 -67

No files matched your search

+42 -2
View File
@@ -14,6 +14,7 @@ import (
"git.kebcloud.no/keb/lazysecrets/internal/match"
"git.kebcloud.no/keb/lazysecrets/internal/provider"
"git.kebcloud.no/keb/lazysecrets/internal/ref"
"git.kebcloud.no/keb/lazysecrets/internal/store"
"git.kebcloud.no/keb/lazysecrets/internal/ui/keys"
"git.kebcloud.no/keb/lazysecrets/internal/ui/panes"
@@ -52,6 +53,12 @@ type searchView struct {
res int // cursor in shown
here string // the scope of the source Go to was opened from, if any
// pick, if set, makes Go to a picker of secrets, for title: it lists
// secrets only, and enter gives the selected one's link to pick
// instead of going there.
pick func(m *Model, r ref.Ref) tea.Cmd
pickTitle, pickNote string
// loaded are the scopes a search has loaded since the popup opened:
// typing loads the scope once, so lists that fail aren't asked for
// again on every key.
@@ -267,6 +274,9 @@ func (v *searchView) match() []option {
}
}
}
if v.pick != nil {
cand = slices.DeleteFunc(slices.Clone(cand), func(o option) bool { _, ok := pickable(o); return !ok })
}
q := v.input.Value()
if q == "" {
return slices.Clone(cand)
@@ -423,9 +433,15 @@ func (m *Model) handleSearch(msg tea.KeyPressMsg) tea.Cmd {
return nil
case key.Matches(msg, k.sel):
switch {
case v.results && v.res < len(v.shown) && v.pick != nil:
r, _ := pickable(v.shown[v.res])
m.search = nil
return v.pick(m, r)
case v.results && v.res < len(v.shown):
m.search = nil
return v.shown[v.res].run(m)
case !v.results && v.pick != nil:
v.results = true // a picker only narrows to the scope
case !v.results && v.onSource():
m.search = nil
return v.scope().run(m)
@@ -745,6 +761,9 @@ func (m Model) searchViewBox() string {
} else {
body = append(body, "") // the same height on every tab
}
if v.pick != nil && v.pickNote != "" {
body = append(body, " "+m.st.Muted.Render(v.pickNote))
}
km := m.keys
var foot string
switch {
@@ -753,17 +772,20 @@ func (m Model) searchViewBox() string {
if v.tab == tabSearch {
hints = append(hints, keyHint{joinKeys(km.SearchSources, km.SearchResults), "switch list"}, hint(km.SearchLoad, "load"))
}
foot = footer(append(hints, hint(km.PopupStar, "star"), hint(km.PopupSelect, "go"), hint(km.PopupClose, "stop typing"))...)
foot = footer(append(hints, hint(km.PopupStar, "star"), hint(km.PopupSelect, v.selectLabel()), hint(km.PopupClose, "stop typing"))...)
default:
hints := []keyHint{move(km.GoUp, km.GoDown), {joinKeys(km.GoPrevTab, km.GoNextTab), "tab"}}
if v.tab == tabSearch {
hints = append(hints, keyHint{joinKeys(km.GoSources, km.GoResults), "list"}, hint(km.GoLoad, "load"), hint(km.GoLoadAll, "load all"))
}
foot = footer(append(hints, hint(km.GoFilter, "filter"), hint(km.GoStar, "star"), hint(km.GoSelect, "go"), hint(km.GoClose, "close"))...)
foot = footer(append(hints, hint(km.GoFilter, "filter"), hint(km.GoStar, "star"), hint(km.GoSelect, v.selectLabel()), hint(km.GoClose, "close"))...)
}
// Tabs in the title, the current one underlined, like the panes.
ts := panes.TitleStyle(m.st, focused)
head := ts.Render(goToTitle + " ")
if v.pick != nil {
head = ts.Render(v.pickTitle + " ")
}
for i, name := range tabNames {
if i > 0 {
head += ts.Render(" - ")
@@ -776,3 +798,21 @@ func (m Model) searchViewBox() string {
}
return panes.Box(m.st, head, foot, body, w, len(body)+2, focused)
}
// selectLabel names what enter does with the selected entry.
func (v *searchView) selectLabel() string {
if v.pick != nil {
return "pick"
}
return "go"
}
// pickable is the link of a Go to entry that a picker can pick: a
// secret (not a key or certificate).
func pickable(o option) (ref.Ref, bool) {
r, err := ref.Parse(o.star)
if err != nil || r.IsShare() || r.IsSource() || r.IsContainer() || (r.Type != "" && r.Type != provider.TypeSecret) {
return ref.Ref{}, false
}
return r, true
}