lsm

module
v0.11.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2026 License: BSD-3-Clause

README

lsm — Local Secrets Manager

A lightweight CLI for managing per-app, per-environment secrets encrypted with age. No remote services, no billing, no accounts.

Install

Homebrew (macOS / Linux)
brew install llbbl/tap/lsm

Recent Homebrew requires trusting a third-party tap once; if the install is refused, run brew trust llbbl/tap and retry (or brew tap llbbl/tap first, then brew install lsm).

Go
go install github.com/llbbl/lsm/cmd/lsm@latest
Curl (Linux / macOS)
curl -fsSL https://raw.githubusercontent.com/llbbl/lsm/main/scripts/install.sh | sh

It downloads the matching archive, verifies its checksum, and installs lsm to ~/.local/bin (override with LSM_BIN; pin a version with LSM_VERSION).

Windows

Download the .zip from the releases page and follow the bundled INSTALL.md.

Quick Start

# 1. Generate encryption key
lsm init

# 2. Register your project
cd ~/Web/myapp
lsm link myapp

# 3. Import existing .env file
lsm import .env.local

# 4. Run with secrets injected
lsm exec -- pnpm dev

# 5. Export for deployment (writes to myapp.production.env)
lsm dump --env production

How It Works

Secrets are stored as age-encrypted .env files in ~/.lsm/:

~/.lsm/
  key.txt                      # age private key (chmod 600)
  config.yaml                  # default env + app registry
  myapp.dev.age                # encrypted secrets
  myapp.production.age
  backend.dev.age

The central config.yaml maps app names to project directories:

env: dev
apps:
    myapp: /Users/you/Web/myapp
    backend: /Users/you/Web/backend

When you run any lsm command, it resolves which app you mean by checking your current directory against this registry.

Commands

lsm init                              # Generate age key pair
lsm link <app>                        # Register current directory as an app
lsm set <KEY> <VALUE>                 # Set a secret (use '-' to read from stdin)
lsm get <KEY>                         # Get a secret value
lsm delete <KEY>                      # Remove a secret
lsm list                              # List secret keys (no values)
lsm dump                              # Export to .env file (masked terminal output)
lsm exec -- <command>                 # Inject secrets and run command
lsm edit                              # Edit secrets in $EDITOR
lsm import <file>                     # Import from .env file (or '-' for stdin)
lsm apps                              # List all registered apps
lsm envs <app>                        # List environments for an app
lsm gh push                           # Push local secrets to GitHub Actions
lsm gh status                         # Compare local secrets with GitHub Actions
GitHub Actions secrets (lsm gh)

lsm gh pushes your locally-encrypted secrets to GitHub Actions and reports drift between the two.

cd ~/Web/myapp        # must be the directory you ran `lsm link` in
lsm gh push                       # set repo Actions secrets from local store
lsm gh push --gh-env production    # target a GitHub environment instead
lsm gh push --prune               # also delete remote secrets no longer local
lsm gh status                     # show in-sync / local-only / remote-only

Requirements and behavior:

  • Directory-bound. lsm gh operates on the app registered for the current directory via lsm link. It does not accept --app; run it from the project root. The repo defaults to the origin remote (override with --repo OWNER/REPO), and the env resolves from --env, .lsm.yaml, or the global default.
  • Requires the GitHub CLI. gh must be installed and authenticated (gh auth login).
  • Values never touch argv or disk. Each value is streamed to gh secret set on stdin; no plaintext temp files, no backup file.
  • Write-only. GitHub's secrets API cannot return secret values. lsm gh status shows secret names and GitHub's update timestamps only — values can never be pulled back from GitHub.

All commands accept --app, --env, and --dir flags to override auto-detection.

See docs/commands.md for detailed usage and examples.

App & Env Resolution

lsm resolves the app name and environment in this order:

  1. CLI flags (--app, --env)
  2. .lsm.yaml in current directory (for backward compatibility)
  3. Central registry lookup by current directory path
  4. Directory name fallback, ~/.lsm/config.yaml for default env

The recommended approach is to use lsm link to register your projects. After linking, lsm automatically knows which app you're working on based on your current directory:

cd ~/Web/myapp
lsm link myapp        # one-time setup

# Now all commands auto-resolve to app=myapp
lsm set DB_URL postgres://localhost
lsm exec -- pnpm dev
lsm dump --env production

Security

  • Age encryption (X25519 + ChaCha20-Poly1305)
  • Private key stays in ~/.lsm/key.txt (chmod 600)
  • exec injects secrets into the subprocess only — not your shell
  • dump masks values in terminal output, writes real values to file only
  • Encrypted at rest — safe for screensharing

Docs

Observability

lsm can optionally emit an audit log of every access and ship it via OTLP to your observability stack (Loki/Grafana, Honeycomb, Datadog, etc.). Off by default — enable via the otlp: block in ~/.lsm/config.yaml.

For users running the LGTM stack, drop-in Grafana dashboard + Loki alert rules live in observability/. lsm itself has no Grafana/Loki dependency; these are pure config artifacts.

Changelog

See CHANGELOG.md for release history. This project uses Conventional Commits and git-cliff for automated changelog generation.

License

BSD 3-Clause. See LICENSE.

Directories

Path Synopsis
cmd
lsm command
internal
audit
Package audit provides a hash-chained, tamper-evident audit log for lsm.
Package audit provides a hash-chained, tamper-evident audit log for lsm.
cmd
dlog
Package dlog is a thin wrapper over log/slog for internal flow tracing.
Package dlog is a thin wrapper over log/slog for internal flow tracing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL