1 Commits
Author SHA1 Message Date
keb 89d49ed1fe fix: unambiguous repo key names, clearer config and key names, and a newer lazysecrets's files no longer stop an older one
CI / Checks (pull_request) Successful in 41s
PR title / Conventional title (pull_request) Successful in 1s
2026-10-13 22:42:15 +02:00
12 changed files with 19 additions and 30 deletions

No files matched your search

+1 -1
View File
@@ -92,7 +92,7 @@ use most:
secret secret
- [Config](docs/config.md): every option, themes, layered configs, the - [Config](docs/config.md): every option, themes, layered configs, the
state file state file
- [Development](docs/development.md): building, tests, how changes land and - [Development](docs/development.md): building, tests, pull requests and
releasing releasing
## Privacy ## Privacy
-11
View File
@@ -1,11 +0,0 @@
# Security
Please report a vulnerability privately, not in a public issue:
- on GitHub, with **Report a vulnerability** under the
[Security tab](https://github.com/karleinarb/lazysecrets/security), or
- by email to karl-einarb@outlook.com.
Say what's affected, how to reproduce it and the version
(`lazysecrets --version`). Fixes go into the next release, and only the
latest release gets them.
+1 -1
View File
@@ -123,7 +123,7 @@ func run() error {
for scripts: VAR=$(lazysecrets get <ref>) for scripts: VAR=$(lazysecrets get <ref>)
lazysecrets [flags] share [--key <secret>] <env file>... lazysecrets [flags] share [--key <secret>] <env file>...
print a link to env files of a repo, encrypted print a link to env files of a repo, encrypted
with a secret's value (default: sharing.key) with a secret's value (default: share.key)
lazysecrets [flags] keybindings print every action and its keys (with your lazysecrets [flags] keybindings print every action and its keys (with your
config applied), as config to copy and edit config applied), as config to copy and edit
lazysecrets handler install [--terminal NAME] lazysecrets handler install [--terminal NAME]
+4 -4
View File
@@ -17,12 +17,12 @@ import (
) )
// shareFiles prints a share link to env files of one repo, encrypted with // shareFiles prints a share link to env files of one repo, encrypted with
// the --key secret's value, else the repo's or the config's sharing.key: // the --key secret's value, else the repo's or the config's share.key:
// //
// lazysecrets share .env apps/api/.env // lazysecrets share .env apps/api/.env
func shareFiles(ctx context.Context, providers []provider.Provider, st *store.Store, general string, rules share.Rules, args []string, out io.Writer) error { func shareFiles(ctx context.Context, providers []provider.Provider, st *store.Store, general string, rules share.Rules, args []string, out io.Writer) error {
fs := flag.NewFlagSet("share", flag.ContinueOnError) fs := flag.NewFlagSet("share", flag.ContinueOnError)
keyLink := fs.String("key", "", "the secret to encrypt with: its lazysecrets:// link, Key Vault URL or reference (default: sharing.key)") keyLink := fs.String("key", "", "the secret to encrypt with: its lazysecrets:// link, Key Vault URL or reference (default: share.key)")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
} }
@@ -73,7 +73,7 @@ func shareFiles(ctx context.Context, providers []provider.Provider, st *store.St
return err return err
} }
if !ok { if !ok {
return errors.New("which secret to encrypt with? --key <secret>, or sharing.key in the repo's .lazysecrets.yaml or the config") return errors.New("which secret to encrypt with? --key <secret>, or share.key in the repo's .lazysecrets.yaml or the config")
} }
v, version, err := readKey(ctx, providers, st, key) v, version, err := readKey(ctx, providers, st, key)
if err != nil { if err != nil {
@@ -87,7 +87,7 @@ func shareFiles(ctx context.Context, providers []provider.Provider, st *store.St
return err return err
} }
// shareRules are the config's sharing.keyRules. // shareRules are the config's share.keyRules.
func shareRules(cfg config.Config) share.Rules { func shareRules(cfg config.Config) share.Rules {
return share.Rules{MinLength: cfg.Sharing.KeyRules.MinLength, MinClasses: cfg.Sharing.KeyRules.MinClasses} return share.Rules{MinLength: cfg.Sharing.KeyRules.MinLength, MinClasses: cfg.Sharing.KeyRules.MinClasses}
} }
+1 -1
View File
@@ -22,7 +22,7 @@ Development builds show `dev-<commit>` as their version (`-dirty` with
uncommitted changes); `go install …@v0.2.0` shows the tag, releases the uncommitted changes); `go install …@v0.2.0` shows the tag, releases the
version they were built for. version they were built for.
## How changes land ## Pull requests
Pull requests into `main` are squash-merged, so each is one commit titled Pull requests into `main` are squash-merged, so each is one commit titled
like the PR. The title is a [conventional commit](https://www.conventionalcommits.org) like the PR. The title is a [conventional commit](https://www.conventionalcommits.org)
+1 -1
View File
@@ -332,7 +332,7 @@ func Azure(delay time.Duration) *Provider {
}, demoCert) }, demoCert)
shared := p.addContainer(prod, "kv-shared-prod", "https://kv-shared-prod.vault.azure.net", allTypes...) shared := p.addContainer(prod, "kv-shared-prod", "https://kv-shared-prod.vault.azure.net", allTypes...)
// A key to share env files with (S → f): random, as sharing.keyRules wants. // A key to share env files with (S → f): random, as share.keyRules wants.
p.add(shared, provider.TypeSecret, provider.Object{ p.add(shared, provider.TypeSecret, provider.Object{
Name: "env-share", Enabled: &yes, Updated: base, Reference: secretRef("kv-shared-prod", "env-share"), Name: "env-share", Enabled: &yes, Updated: base, Reference: secretRef("kv-shared-prod", "env-share"),
}, "q8Zt3VwL1mXc7Rk2Pj9Ys4Hn6Bf0Ga5Ud+Te/OiWlE=") }, "q8Zt3VwL1mXc7Rk2Pj9Ys4Hn6Bf0Ga5Ud+Te/OiWlE=")
+1 -1
View File
@@ -607,7 +607,7 @@ type lazysecretsFile struct {
} `yaml:"sharing"` } `yaml:"sharing"`
} }
// ShareKey is the sharing.key of the repo's .lazysecrets.yaml, if any. // ShareKey is the share.key of the repo's .lazysecrets.yaml, if any.
func ShareKey(root string) (string, error) { func ShareKey(root string) (string, error) {
b, err := os.ReadFile(filepath.Join(root, ".lazysecrets.yaml")) b, err := os.ReadFile(filepath.Join(root, ".lazysecrets.yaml"))
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
+1 -1
View File
@@ -53,7 +53,7 @@ func (r Rules) Check(key []byte) error {
if len(has) == 0 { if len(has) == 0 {
return nil return nil
} }
return fmt.Errorf("its value has %s; sharing.keyRules needs %s", return fmt.Errorf("its value has %s; share.keyRules needs %s",
strings.Join(has, " and "), strings.Join(needs, " and ")) strings.Join(has, " and "), strings.Join(needs, " and "))
} }
+3 -3
View File
@@ -259,8 +259,8 @@ func CheckPath(p string) error {
return nil return nil
} }
// DefaultKey is the key for a repo's files: sharing.key in the repo's // DefaultKey is the key for a repo's files: share.key in the repo's
// .lazysecrets.yaml, else general (sharing.key in the config). ok is false // .lazysecrets.yaml, else general (share.key in the config). ok is false
// when neither names one. // when neither names one.
func DefaultKey(root, general string) (key ref.Ref, ok bool, err error) { func DefaultKey(root, general string) (key ref.Ref, ok bool, err error) {
link, err := repo.ShareKey(root) link, err := repo.ShareKey(root)
@@ -276,7 +276,7 @@ func DefaultKey(root, general string) (key ref.Ref, ok bool, err error) {
} }
key, err = ParseKey(link) key, err = ParseKey(link)
if err != nil { if err != nil {
return ref.Ref{}, false, fmt.Errorf("sharing.key in %s: %w", where, err) return ref.Ref{}, false, fmt.Errorf("share.key in %s: %w", where, err)
} }
return key, true, nil return key, true, nil
} }
+3 -3
View File
@@ -87,7 +87,7 @@ type Options struct {
// CacheFile keeps what was loaded between runs; "" keeps it for this // CacheFile keeps what was loaded between runs; "" keeps it for this
// run only. // run only.
CacheFile string CacheFile string
// ShareKey is the config's sharing.key: the secret that encrypts shared // ShareKey is the config's share.key: the secret that encrypts shared
// env files, for repos whose .lazysecrets.yaml names none. // env files, for repos whose .lazysecrets.yaml names none.
ShareKey string ShareKey string
// ShareRules are what a key's value must be to share with it. // ShareRules are what a key's value must be to share with it.
@@ -284,8 +284,8 @@ type Model struct {
linked []provider.Container // vaults opened from links, this session linked []provider.Container // vaults opened from links, this session
open *ref.Ref // reference to open at startup open *ref.Ref // reference to open at startup
shareKey string // the config's sharing.key shareKey string // the config's share.key
shareRules share.Rules // and sharing.keyRules shareRules share.Rules // and share.keyRules
// A lazysecrets:// link found on the clipboard, offered in the footer. // A lazysecrets:// link found on the clipboard, offered in the footer.
dismissedLink string // the last link offered: not offered again dismissedLink string // the last link offered: not offered again
+1 -1
View File
@@ -38,7 +38,7 @@ type shareFilesMsg struct {
type sealedMsg struct { type sealedMsg struct {
link ref.Ref link ref.Ref
n int n int
// from is the picker the key was picked in; nil for sharing.key's. // from is the picker the key was picked in; nil for share.key's.
from *picker from *picker
err error err error
} }
+2 -2
View File
@@ -50,7 +50,7 @@ func shareFrom(t *testing.T, root string, paste bool) string {
t.Fatalf("selected %v, want the repo", src.ID) t.Fatalf("selected %v, want the repo", src.ID)
} }
d.keys("S", "f") d.keys("S", "f")
// No sharing.key set: it asks which secret, in Go to, which lists // No share.key set: it asks which secret, in Go to, which lists
// only secrets. // only secrets.
v := d.m.search v := d.m.search
if v == nil || v.picker == nil { if v == nil || v.picker == nil {
@@ -218,7 +218,7 @@ func TestShareInDemo(t *testing.T) {
} }
// Too short a key: the picker stays, saying why. // Too short a key: the picker stays, saying why.
d.send(tea.PasteMsg{Content: "https://kv-app-prod.vault.azure.net/secrets/db-password"}) d.send(tea.PasteMsg{Content: "https://kv-app-prod.vault.azure.net/secrets/db-password"})
if d.m.search == nil || !strings.Contains(d.m.search.picker.err, "Can't use db-password: its value has 28 characters; sharing.keyRules needs 32 (minLength)") { if d.m.search == nil || !strings.Contains(d.m.search.picker.err, "Can't use db-password: its value has 28 characters; share.keyRules needs 32 (minLength)") {
t.Fatalf("not said in the picker: %v\n%s", d.m.search != nil, d.screen()) t.Fatalf("not said in the picker: %v\n%s", d.m.search != nil, d.screen())
} }
if !strings.Contains(d.screen(), "28 characters") { if !strings.Contains(d.screen(), "28 characters") {