feat: share env files as encrypted links
CI / Checks (pull_request) Failing after 10s
PR title / Conventional title (pull_request) Successful in 0s

S → f on a repo, an env file or a key in one copies a
lazysecrets://share link holding the env files, encrypted (age) with
a secret's value: whoever can read that secret can open it. The key is
share.key in the repo's .lazysecrets.yaml, else in the config, else
picked when sharing; on Azure the link pins its version. Opening one
says what it holds, decrypts when asked, and saves the files in the
clone of the repo (or a folder chosen), replacing existing ones only
when asked. lazysecrets share prints a link from the command line.

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 11:59:39 +02:00
1 parent 1a5e40a012
commit 4b2f685921
26 files changed
+1541 -98

No files matched your search

+37 -6
View File
@@ -311,8 +311,8 @@ func (p *Provider) Containers(ctx context.Context, src provider.Source) ([]provi
c.Detail = "sops · " + strings.Join(meta.methods, ", ")
case isSops:
return // a SOPS file where .sops.yaml says SOPS files don't go
case isEnv(f):
c.Detail = "env · plain text"
case IsEnv(f):
c.Detail = provider.DetailPlainEnv
default:
return
}
@@ -464,6 +464,16 @@ func (p *Provider) Locate(_ context.Context, host string) (string, bool, error)
return "", false, nil
}
// Root is the root of the git repo dir is in, and the repo's ID: its
// remote without scheme or .git (a repo link's host), else the root.
func Root(dir string) (root, id string, err error) {
root, err = gitRoot(dir)
if err != nil {
return "", "", fmt.Errorf("%s isn't in a git repository", dir)
}
return root, info(root, "").id, nil
}
// --- git ---
func gitRoot(dir string) (string, error) {
@@ -568,6 +578,27 @@ func normalizeRemote(remote string) (string, string) {
type lazysecretsFile struct {
Include []string `yaml:"include"`
Exclude []string `yaml:"exclude"`
Share struct {
// Key is the link to the secret that encrypts the repo's
// shared env files (package share).
Key string `yaml:"key"`
} `yaml:"share"`
}
// ShareKey is the share.key of the repo's .lazysecrets.yaml, if any.
func ShareKey(root string) (string, error) {
b, err := os.ReadFile(filepath.Join(root, ".lazysecrets.yaml"))
if errors.Is(err, os.ErrNotExist) {
return "", nil
}
if err != nil {
return "", err
}
var f lazysecretsFile
if err := yaml.Unmarshal(b, &f); err != nil {
return "", fmt.Errorf("%s/.lazysecrets.yaml: %w", root, err)
}
return f.Share.Key, nil
}
// selector says which files to look at: user (the include/exclude of the
@@ -618,7 +649,7 @@ func envFiles(root string, tracked []string) []string {
dirs := map[string]bool{".": true}
for _, f := range tracked {
isTracked[f] = true
if isEnv(f) {
if IsEnv(f) {
out = append(out, f)
}
if d := path.Dir(f); !dirs[d] && !inPackages(f) {
@@ -632,7 +663,7 @@ func envFiles(root string, tracked []string) []string {
}
for _, e := range entries {
f := path.Join(d, e.Name())
if e.Type().IsRegular() && !isTracked[f] && isEnv(f) {
if e.Type().IsRegular() && !isTracked[f] && IsEnv(f) {
out = append(out, f)
}
}
@@ -663,10 +694,10 @@ func inPackages(f string) bool {
return false
}
// isEnv reports whether a file is named like an env file with real values:
// IsEnv reports whether a file is named like an env file with real values:
// .env, .env.local, prod.env; not .env.example and the like, nor one in
// dependencies.
func isEnv(f string) bool {
func IsEnv(f string) bool {
if inPackages(f) {
return false
}