Files
lazysecrets/internal/provider/provider.go
T
kebandClaude Opus 5.5 6fab41703e
Release / Build and publish (push) Successful in 22s
Hello world 👋
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 23:58:25 +02:00

172 lines
5.5 KiB
Go

// Package provider defines the read-only interface every secret backend
// implements, and the types the UI works with.
//
// All backends map onto the same hierarchy:
//
// Source Azure subscription | Databricks workspace profile
// Container Key Vault | secret scope
// Object secret, key or certificate | secret
package provider
import (
"context"
"errors"
"fmt"
"time"
)
// Kind identifies a backend.
type Kind string
const (
KindAzure Kind = "Azure"
KindDatabricks Kind = "Databricks"
// KindRepo is a git repository's encrypted secret files (SOPS).
KindRepo Kind = "Repo"
)
// AuthError reports that the user must (re)authenticate with a backend, for
// example because their az CLI login has expired.
type AuthError struct {
Kind Kind
// Account names the identity when a provider has several, e.g.
// "Azure · admin.alice"; empty otherwise.
Account string
// Login is the command that signs the user in, e.g. ["az", "login"].
Login []string
Err error
}
func (e *AuthError) Error() string {
return fmt.Sprintf("%s: not signed in or session expired: %v", e.Who(), e.Err)
}
// Who is the account, or the kind if there is just one.
func (e *AuthError) Who() string {
if e.Account != "" {
return e.Account
}
return string(e.Kind)
}
func (e *AuthError) Unwrap() error { return e.Err }
// ErrUnsupported is returned by optional operations a backend cannot perform,
// such as listing versions of a Databricks secret.
var ErrUnsupported = errors.New("not supported by this provider")
// Source is a top-level account: an Azure subscription or a Databricks
// workspace profile.
type Source struct {
Kind Kind
// Provider is the ID of the provider instance the source came from.
// The app sets it; it routes requests when several providers share a
// Kind, e.g. one per Azure account.
Provider string
// ProviderLabel is that provider's Label, also set by the app.
ProviderLabel string
ID string
Name string
Detail string // e.g. tenant or workspace host
URL string // web page for the source, if any
// Here marks the source lazysecrets was started in (the current git
// repo): listed first, starred or not, and labelled.
Here bool
}
// ObjectType is the kind of object stored in a container.
type ObjectType string
const (
TypeSecret ObjectType = "Secret"
TypeKey ObjectType = "Key"
TypeCertificate ObjectType = "Certificate"
)
// Container holds objects: a Key Vault or a Databricks secret scope.
type Container struct {
Source Source
ID string
Name string
Detail string // e.g. vault URL, or "Azure Key Vault-backed: kv-name"
// Types lists the object types the container holds; empty means
// secrets only.
Types []ObjectType
URL string // web page for the container, if any
}
// ObjectTypes returns the container's object types, defaulting to secrets.
func (c Container) ObjectTypes() []ObjectType {
if len(c.Types) == 0 {
return []ObjectType{TypeSecret}
}
return c.Types
}
// Attr is a type-specific metadata field, shown in provider order.
type Attr struct {
Label string
Value string
}
// Object describes a secret, key or certificate without its value.
type Object struct {
Container Container
Type ObjectType
ID string
Name string
Version string
Enabled *bool
Updated time.Time
Expires time.Time
ContentType string
Tags map[string]string
// Attrs holds type-specific metadata, e.g. key type and size, or a
// certificate's subject, issuer and thumbprint.
Attrs []Attr
// Reference is how the object is referenced from config, e.g.
// "@Microsoft.KeyVault(SecretUri=...)" or "{{secrets/scope/key}}".
Reference string
URL string // web page for the object (or its list), if any
}
// Provider is a read-only secret backend. Every method may block on the
// network and must honour ctx cancellation.
type Provider interface {
Kind() Kind
// ID identifies the instance, stable across runs, e.g. "Azure" or
// "Azure:user@example.com/tenant".
ID() string
// Label names the instance in the UI, e.g. "Azure" or "Azure · user".
Label() string
Sources(ctx context.Context) ([]Source, error)
Containers(ctx context.Context, src Source) ([]Container, error)
// Objects lists objects of type t, one of c.ObjectTypes(). It returns
// metadata only; values are fetched with Value.
Objects(ctx context.Context, c Container, t ObjectType) ([]Object, error)
// Describe returns o with details that listing doesn't include, such as
// a key's type or a certificate's subject. It never fetches secret
// values; it may return o unchanged.
Describe(ctx context.Context, o Object) (Object, error)
// Versions may return ErrUnsupported.
Versions(ctx context.Context, o Object) ([]Object, error)
// Value returns a secret's value, or the public material of a key (PEM
// public key) or certificate (PEM certificate). Private key material is
// never returned for keys.
Value(ctx context.Context, o Object) (SecretValue, error)
}
// Current is implemented by providers that know the source lazysecrets
// was started in (the current git repo) and can find it faster than
// Sources lists everything, so it shows first.
type Current interface {
Current(ctx context.Context) (Source, bool)
}
// Locator is implemented by providers that can find where a container lives,
// to open links. address is a vault host (kv.vault.azure.net) or a
// workspace host. It returns the ID of the source holding it.
type Locator interface {
Locate(ctx context.Context, address string) (sourceID string, ok bool, err error)
}