feat: lazysecrets list marks expiring and expired secrets, and its JSON has expires and enabled

This commit is contained in:
keb committed 2026-10-14 21:24:01 +02:00
1 parent 33fa064104
commit b4e4c1515b
5 files changed
+80 -37

No files matched your search

+38 -16
View File
@@ -41,7 +41,7 @@ import (
// follows as it loads. A list that can't be read is a line too, as it
// fails: the vault or source, then ✗ and why in the theme's error colour.
// They're in the output rather than on stderr, which would draw over fzf.
func listCmd(providers []provider.Provider, st *store.Store, cachePath string, timeout func(provider.Kind) time.Duration, theme styles.Styles, withIcons, withRecent bool, args []string, out io.Writer) error {
func listCmd(providers []provider.Provider, st *store.Store, cachePath string, timeout func(provider.Kind) time.Duration, theme styles.Styles, withIcons, withRecent bool, expiryWarn time.Duration, args []string, out io.Writer) error {
fs := flag.NewFlagSet("list", flag.ContinueOnError)
cached := fs.Bool("cached", false, "only what's cached, and repos: load nothing from Azure or Databricks")
maxAge := fs.Duration("max-age", 2*time.Minute, "load cached lists older than this again")
@@ -50,6 +50,7 @@ func listCmd(providers []provider.Provider, st *store.Store, cachePath string, t
iconsOn := fs.Bool("icons", withIcons, "put the provider's Nerd Font icon before names (text)")
stars := fs.Bool("stars", true, "put ★ before starred names, in the theme's favouriteColor (text)")
recent := fs.Bool("recent", withRecent, "put ◷ before names used lately, in mutedColor (text; default ui.recentIcon)")
expiry := fs.Bool("expiry", true, "put ⚠ before names expiring within ui.expiryWarningDays, ✗ before expired ones (text)")
kinds := fs.String("kind", "", "only these kinds, comma-separated: "+strings.Join(listing.Kinds, ", ")+" (vault: also scopes and repo files)")
showErrors := fs.Bool("errors", true, "list the lists that can't be read, with why (text: ✗ lines; json: \"error\")")
if err := fs.Parse(args); err != nil {
@@ -71,16 +72,17 @@ func listCmd(providers []provider.Provider, st *store.Store, cachePath string, t
if *color != "always" && *color != "never" {
return fmt.Errorf("--color: %q is not always or never", *color)
}
iconSet := icons.None
m := marks{theme: theme, icons: icons.None, stars: *stars, recent: *recent, expiry: *expiry,
color: *color == "always", warn: expiryWarn, now: time.Now()}
if *iconsOn {
iconSet = icons.NerdFont
m.icons = icons.NerdFont
}
var write func(listing.Entry) error
switch *format {
case "text":
write = func(e listing.Entry) error {
colored := *color == "always"
mark := markOf(e, theme, iconSet, *stars, *recent, colored)
mark := m.of(e)
name := nameOf(e, theme, colored)
why := errorOf(e, theme, colored)
// A tab or line break in a name would break the line up.
@@ -165,12 +167,21 @@ func nameOf(e listing.Entry, theme styles.Styles, color bool) string {
return name
}
// markOf is what goes before the name, in a field of its own so a search
// leaves it out: ★ for a starred entry and ◷ for one used lately (as the
// TUI marks them; a space as wide for the rest, so names line up), and
// the provider's icon.
func markOf(e listing.Entry, theme styles.Styles, iconSet icons.Set, stars, recent, color bool) string {
render := renderer(color)
// marks says what goes before the name, in a field of its own so a
// search leaves it out: ★ for a starred entry, ◷ for one used lately,
// ⚠ for one expiring within warn and ✗ for an expired one (as the TUI
// marks them; a space as wide where it isn't, so names line up), then the
// provider's icon.
type marks struct {
theme styles.Styles
icons icons.Set
stars, recent, expiry, color bool
warn time.Duration // ui.expiryWarningDays
now time.Time
}
func (m marks) of(e listing.Entry) string {
render := renderer(m.color)
var parts []string
mark := func(on bool, st lipgloss.Style, s string) {
if !on {
@@ -178,11 +189,22 @@ func markOf(e listing.Entry, theme styles.Styles, iconSet icons.Set, stars, rece
}
parts = append(parts, render(st, s))
}
if stars {
mark(e.Starred, theme.Favourite, "★")
if m.stars {
mark(e.Starred, m.theme.Favourite, "★")
}
if recent {
mark(e.Recent, theme.Muted, "◷")
if m.recent {
mark(e.Recent, m.theme.Muted, "◷")
}
if m.expiry {
left := e.Expires.Sub(m.now)
switch {
case e.Expires.IsZero() || left > m.warn:
mark(false, m.theme.Muted, "")
case left <= 0:
mark(true, m.theme.Error, "✗")
default:
mark(true, m.theme.Warning, "⚠")
}
}
kind := provider.Kind("")
for _, k := range []provider.Kind{provider.KindAzure, provider.KindDatabricks, provider.KindRepo} {
@@ -190,8 +212,8 @@ func markOf(e listing.Entry, theme styles.Styles, iconSet icons.Set, stars, rece
kind = k
}
}
if icon := strings.TrimSpace(iconSet.Prefix(kind)); icon != "" {
parts = append(parts, render(theme.Kind(kind), icon))
if icon := strings.TrimSpace(m.icons.Prefix(kind)); icon != "" {
parts = append(parts, render(m.theme.Kind(kind), icon))
}
return strings.Join(parts, " ")
}