feat: l for details; details for vaults, scopes and files; getting started; the age of cached lists (#17)

- `l` goes to the details of what is selected; `enter` still drills in
- vaults, scopes and files show their details (vault settings from the listing, no extra requests)
- with nothing to show, the right pane says how to get started
- a list from the cache says how old it is while it reloads
- what is expiring, in the status pane and `lazysecrets expiring`
- when access is refused, what to check, for Azure and Databricks
- no group list in an account's details, and no Microsoft Graph call for it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #17.
This commit is contained in:
kebandClaude Opus 5.5 committed 2026-10-11 14:24:08 +02:00
1 parent 9b0329e9da
commit 09bacd8438
32 files changed
+1321 -254

No files matched your search

+7 -13
View File
@@ -9,7 +9,6 @@ import (
"crypto/x509"
"errors"
"fmt"
"net/http"
"regexp"
"slices"
"strings"
@@ -37,12 +36,11 @@ var objectTypes = []provider.ObjectType{provider.TypeSecret, provider.TypeKey, p
type Provider struct {
id, label string // "" for the single-account defaults
cred azcore.TokenCredential
opts options
account *accountDetails // nil for a service principal from AZURE_*
graphClient *http.Client // for Groups; nil for the default
subs *armsubscriptions.Client
graph *armresourcegraph.Client
cred azcore.TokenCredential
opts options
account *accountDetails // nil for a service principal from AZURE_*
subs *armsubscriptions.Client
graph *armresourcegraph.Client
mu sync.Mutex
vaults map[string]*vaultClients // by vault URL
@@ -185,10 +183,6 @@ func (p *Provider) tenant(subscriptionID string) string {
return p.tenants[subscriptionID]
}
const vaultQuery = `resources
| where type =~ 'microsoft.keyvault/vaults'
| project id, name, uri = tostring(properties.vaultUri)`
func (p *Provider) graphVaults(ctx context.Context, src provider.Source) ([]provider.Container, error) {
var out []provider.Container
req := armresourcegraph.QueryRequest{
@@ -228,7 +222,7 @@ func graphVault(src provider.Source, row any) (provider.Container, bool) {
if id == "" || name == "" || uri == "" {
return provider.Container{}, false
}
return provider.Container{Source: src, ID: id, Name: name, Detail: uri, Types: objectTypes}, true
return provider.Container{Source: src, ID: id, Name: name, Detail: uri, Types: objectTypes, Attrs: graphInfo(m).attrs()}, true
}
func (p *Provider) armVaults(ctx context.Context, src provider.Source) ([]provider.Container, error) {
@@ -249,7 +243,7 @@ func (p *Provider) armVaults(ctx context.Context, src provider.Source) ([]provid
}
out = append(out, provider.Container{
Source: src, ID: deref(v.ID), Name: deref(v.Name),
Detail: *v.Properties.VaultURI, Types: objectTypes,
Detail: *v.Properties.VaultURI, Types: objectTypes, Attrs: armInfo(v).attrs(),
})
}
}