Skip to content

Lpassrc

Dennis Lee edited this page May 28, 2026 · 2 revisions

title: lpassrc radar_quadrant: Tools radar_ring: Trial radar_position: inner source_url: https://github.com/dennislwm/bash-alias-custom

lpassrc

lpassrc is a custom Bash function library providing full CRUD lifecycle management of LastPass Secure Notes used as shell environment stores. It lives in the bash-alias-custom project and extends the read-only pattern established by lpass-env with a write-capable admin tier.

Function Surface

The library is split into two tiers. The lp_ prefix covers read-oriented functions safe to call at any time: lp_env_export (lpex) loads all KEY=VALUE pairs from a named Secure Note into the current shell via eval; lp_env_shell (lpes) launches a subshell with vars isolated from the parent environment; lp_login (lpl) handles interactive authentication.

The lpa_ prefix covers admin functions that modify the LastPass vault. lpa_env_add (lpaa) bootstraps a new Secure Note from stdin — one-shot, blocked by a duplicate guard on subsequent calls. lpa_env_edit (lpae) merges incoming KEY=VALUE pairs into an existing note, with incoming keys winning and unmentioned keys preserved. lpa_env_del (lpad) removes named keys; it accepts a -f flag for non-interactive use in scripts.

Note names are auto-resolved from the current git remote via lpa_default_note, producing a stable <repo-name>/env path across all clones of the same repository.

Design Decisions

The library uses eval "$(lpass show --notes <group/name>)" as the load mechanism, treating note content as trusted input — the same pattern as lpass-env. Note content must be bare KEY=value pairs; shell keywords such as export must not appear. Values may contain command substitutions, which eval preserves by design.

All functions check lpass status --quiet before proceeding, preventing misleading errors on expired sessions and protecting piped stdin from being consumed by a failed auth check. Write functions call lpass sync internally; callers are not responsible for syncing.

lpa_env_edit is idempotent: a no-change run produces [SKIP] no changes and makes no network calls. lpa_env_del is idempotent when specified keys are already absent. lpa_env_add is intentionally non-idempotent — the duplicate guard enforces one-shot bootstrap semantics.

Temporary files created during lpa_env_edit merge processing are created with restricted permissions and removed before the function returns under both success and failure paths. On macOS, /tmp persists across reboots, making cleanup a hard requirement.

Agent and Auto-Load

lpass CLI spawns a background agent on first successful login. Subsequent commands use the agent for decryption without prompting. Setting LPASS_AGENT_TIMEOUT=0 prevents the agent from expiring. The agent does not survive a reboot; one manual lpass login is required after each restart before auto-load can succeed.

Secret loading operates on two deliberate layers. The first layer is a shell-level block appended to ~/.bash_profile that calls lpex global/env at every shell startup, injecting cross-project credentials present in every terminal. The second layer loads project-specific variables on demand, scoped to a single working session using the per-project <repo-name>/env note name resolved by lpa_default_note.

The global note is hardcoded as global/env rather than derived from the current repository. This ensures stability across machines where the remote URL may differ and avoids ambiguity outside a git context.

Setup appends the ~/.bash_profile block exactly once, identified by a sentinel comment. Re-running setup detects the sentinel and skips without modifying the file. make status reports whether the sentinel is present; a missing sentinel indicates setup has not been run on the current machine.

Setting LPASS_AGENT_TIMEOUT=0 extends vault access indefinitely until the next reboot or until the agent is manually killed. On an unlocked or compromised machine, all secrets accessible to the agent remain exposed. Users on shared or high-risk machines should consider a shorter timeout or set LPASS_AGENT_DISABLE=1, accepting a password prompt on every vault access.

The auto-load layer is modelled on the existing Varlock pattern. Both append a guarded block to ~/.bash_profile and expose a make status check. The long-term intent is for lpassrc to supersede Varlock; Varlock's integration is limited to 1Password, while lpassrc supports LastPass, the vault in active use.

Radar Assessment

lpassrc is placed in Trial at inner position. The auto-load block is implemented and running in production: lpex global/env executes at every shell startup via ~/.bash_profile, confirming production use of the load path. lpa_env_add has confirmed production use on the write side. Together these clear the Trial gate.

The CRUD pipeline remains well-designed: explicit idempotency contracts, login guard on all functions, temp-file discipline, merge semantics in lpa_env_edit, and a -f flag for non-interactive scripting. The write functions lpae and lpad are built and tested but not yet exercised on a live project beyond lpa_env_add. The inner position reflects this partial production coverage; Adopt is contingent on a complete project cycle exercising the full write tier.

lpassrc is the natural complement to lpass-env, which is read-only and carries a known eval quoting bug. Where lpass-env loads, lpassrc manages. The long-term trajectory is for lpassrc to supersede Varlock as the vault in active use migrates from 1Password to LastPass.

Distribution Model

lpassrc is currently distributed via git clone and git pull across two personal machines (work MacBook, home Mac Mini). This is sufficient for the current use case: both machines are controlled environments where git pull in the bash-alias-custom repo picks up function changes automatically.

A Homebrew tap was evaluated and deferred. As a shell script, lpassrc is not subject to macOS Gatekeeper, so the signing and notarisation pipeline of MacOSCLIDistribution offers no benefit. A simple tap via DistributingScriptsViaHomebrew would work, but requires a separate homebrew-tap repo and a release pipeline to keep the formula's URL and SHA256 in sync with each tag — overhead that outweighs the convenience for two personal machines. Revisit if the number of machines grows or the library is shared with others.

Clone this wiki locally