Skip to content

Latest commit

Β 

History

39 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Avar

Secrets, but automatic.

Avar is a developer-first CLI that makes project secrets invisible, automatic, and shareable β€” without .env files, plaintext on disk, or a central server.

It does three things:

  • Local encrypted vault β€” your secrets, encrypted at rest under your passphrase.
  • Project-aware activation β€” cd into a project and the right secrets appear as environment variables. Leave and they disappear.
  • Multi-recipient bundles β€” commit an encrypted bundle to git; teammates with the right key decrypt it. No shared passphrase.

Clone a repo β†’ open terminal β†’ unlock once β†’ secrets just work.

No plaintext on disk. No external service. No telemetry.


How it's built

Two crypto layers at two storage levels:

Layer Format Purpose
Vault (local) AVR1 envelope: scrypt KDF + chacha20poly1305 AEAD Your local secret store, encrypted to your passphrase.
Bundle (team) age multi-recipient envelope + Ed25519 signature Encrypted file in your repo. Each recipient unwraps with their own key; decrypt verifies the writer's signature.

Trust is explicit. Untrusted projects and bundles fail loudly rather than silently leaking. Each user has their own X25519 + Ed25519 keypair, generated on first bundle command and encrypted at rest with the user's vault passphrase.


Installation

From source

cargo install --git https://github.com/udaysinh-git/avar

Latest commit on main. Requires Rust 1.85+ (edition 2024).

Pre-built binaries

Tagged releases attach prebuilt binaries for Linux x86_64, macOS (Intel + Apple Silicon), and Windows x86_64. See the releases page.

# Linux / macOS β€” substitute TAG and TARGET for your release/platform.
TAG=v0.2.0
TARGET=x86_64-unknown-linux-gnu
curl -L "https://github.com/udaysinh-git/avar/releases/download/${TAG}/avar-${TAG}-${TARGET}.tar.gz" \
  | tar xz
sudo mv avar /usr/local/bin/
# Windows
$tag    = "v0.2.0"
$target = "x86_64-pc-windows-msvc"
Invoke-WebRequest "https://github.com/udaysinh-git/avar/releases/download/$tag/avar-$tag-$target.zip" `
  -OutFile avar.zip
Expand-Archive avar.zip -DestinationPath .
# Move avar.exe somewhere on PATH.

Both build paths produce a single static binary. No background service, no daemon.


Quick Start

Solo flow (just you, just a vault)

avar init                          # create vault + set passphrase
avar add PASSWORD              # piped or prompted
avar project init PASSWORD     # tell this project which secrets it uses
avar unlock                        # prints: export PASSWORD='...'
eval "$(avar unlock)"              # or this, to actually set them in your shell
avar run -- npm start              # or this, to inject into a child command

Team flow (you + teammates, via a bundle)

On the project owner's machine:

avar init                          # if not done already
avar add PASSWORD              # local vault entry
avar project init PASSWORD
avar bundle init                   # creates .avar/secrets.bundle, you are the only recipient
avar bundle add PASSWORD       # pulls from vault, encrypts into bundle

Teammate sends you their public key (from avar bundle share on their machine):

avar bundle share --add age1xyz...
git add .avar && git commit -m "share secrets with teammate"

On the teammate's machine, after pulling:

avar bundle import                 # decrypts, shows you what's in it, prompts y/N
avar unlock                        # works β€” sources from the bundle, not your local vault

Auto-activate on cd (optional)

# in ~/.bashrc or ~/.zshrc
eval "$(avar hook bash)"
# in $PROFILE
Invoke-Expression (& avar hook pwsh | Out-String)

After that, cding into any avar project loads its secrets, and cding out unsets them. Passphrase is prompted at most once per project transition.


Commands

Vault (local):

  • avar init β€” create the vault and set the passphrase.
  • avar add NAME β€” add a secret (value from stdin / prompt).
  • avar get NAME β€” print a secret to stdout.
  • avar list / avar remove NAME.

Project:

  • avar project init [NAMES...] β€” declare which vault secrets this project uses (writes .avar/project.toml).
  • avar env list | add NAME [SECRETS...] | remove NAME β€” manage named environments.

Activation:

  • avar unlock [--shell bash|zsh|fish|pwsh] [--env NAME] β€” print shell-export lines for the project's secrets.
  • avar run [--env NAME] -- <cmd> [args...] β€” run a command with secrets injected; values never appear in any stream.
  • avar hook <bash|zsh|fish|pwsh> β€” emit the rc-file install snippet for auto-activation on cd.
  • avar export <shell> / avar deactivate β€” used by the hook to diff against / clear the previously-loaded project.

Bundle (team):

  • avar bundle init [--recipient AGE_KEY]... β€” create the bundle, you + extras as recipients.
  • avar bundle add NAME / avar bundle remove NAME β€” copy a secret from your vault into the bundle, or drop it.
  • avar bundle share [--add KEY | --remove KEY] β€” no args: print your public key. With flags: manage recipients.
  • avar bundle import [--trust] β€” first-time explicit trust of a bundle someone shared with you.
  • avar bundle inspect [PATH] β€” show recipients, creator, signature, secret names, sha256 β€” without recording trust or echoing values.
  • avar bundle unlock [--shell] [--env] β€” bundle-mode unlock.

Identity (per-user X25519 + Ed25519 keypair, auto-generated on first bundle command):

  • avar identity show | export β€” print your public / private key (private goes to stderr with a warning).
  • avar identity generate β€” print a fresh keypair to stdout without touching disk; for minting CI / service identities.
  • avar identity import [--force] β€” read an age secret key from stdin and store it as this machine's identity.
  • avar identity rotate [--dry-run] β€” replace your keypair; re-encrypts and re-signs bundles you created, lists external bundles that need the owner's action.

Audit (tamper-evident local log):

  • avar audit log [--last N] / avar audit verify β€” read entries or walk the chain.
  • avar audit prune --before <RFC3339> β€” archive old entries, re-chain the kept tail.
  • avar audit export [--format csv|json] β€” emit for grep / jq.

Trust + diagnostics:

  • avar trust list / avar trust revoke <path> β€” manage the on-disk trust store.
  • avar doctor β€” read-only diagnostic dump (vault, identity, trust, audit chain, project context). Never prompts.

Project config

.avar/project.toml:

version = 1

# Simple mode
secrets = ["PASSWORD", "API_KEY"]

# OR multi-env (mutually exclusive with top-level secrets):
default_env = "dev"
[env.dev]
secrets = ["PASSWORD"]
[env.prod]
secrets = ["PASSWORD", "DATADOG_KEY"]

# When using a bundle (added automatically by `avar bundle init`):
bundle = ".avar/secrets.bundle"

Env selection: --env flag β†’ AVAR_ENV env var β†’ default_env field. The shell hook respects AVAR_ENV and re-loads on env change.


Trust model

Two independent trust gates, both stored in $AVAR_HOME/trusted_projects.toml:

  • Project trust β€” keyed on (canonical project root, sha256(project.toml)). Auto-recorded by project init (typing names = consent). Prompts on first encounter or content change. --trust flag and AVAR_TRUST=yes env var accept non-interactively.
  • Bundle trust β€” keyed on (canonical project root, sha256(bundle file)). Never auto-prompts on the recipient side β€” only bundle init (creator) and bundle import (recipient explicit consent) record bundle trust. A changed bundle bails with "run avar bundle import" rather than silently re-prompting.

Environment variables

For interactive use you don't need any of these.

  • AVAR_HOME β€” override the vault location (default is the platform's per-user config dir).
  • AVAR_PASSPHRASE β€” supply the passphrase non-interactively (CI / scripts).
  • AVAR_IDENTITY β€” supply an AGE-SECRET-KEY-1... private key directly. Bypasses on-disk identity entirely; identity-only bundle ops (init, share, import, unlock) need no vault at all. The CI path.
  • AVAR_TRUST β€” accept project-trust prompts non-interactively (yes/y/true/1).
  • AVAR_ENV β€” pick an environment when the project has multiple.

Security model

  • Modern authenticated encryption (scrypt + ChaCha20-Poly1305 for the vault; age for bundles).
  • Each bundle carries an Ed25519 signature by the writer over its canonical bytes; decrypt verifies against the embedded creator pubkey. A creator change between trust events is surfaced to the recipient as *** CREATOR CHANGED ***.
  • No plaintext persistence; values stay in process memory only.
  • Session-only environment injection; values are cleared on cd out.
  • Per-user X25519 + Ed25519 keypair; no passphrase shared between users.
  • Explicit trust on first use for projects and bundles.
  • Vault entries' AEAD tag detects tampering. Each encryption uses fresh salt + nonce.
  • Append-only sha256-chained audit log; avar audit verify walks the chain.
  • Windows DACL hardening on the canary file (inheritance broken, current-user-only ACE); CI asserts this on every push.

Status

Latest tag: v0.2.0. Phases 1 – 3 of the design doc are essentially complete: local vault, project activation, multi-env, shell hook (bash/zsh/fish/pwsh), signed multi-recipient bundles, identity rotate, CI / service-identity flow (AVAR_IDENTITY), tamper-evident audit log with prune + export, doctor + bundle inspect, explicit two-gate trust.

Next: TUI, pluggable sync backends.

This is pre-1.0. Format versions are pinned but may evolve. Issues and PRs welcome.


License

Apache License 2.0.


About

Built by WeLabs, focused on developer-first infrastructure.

About

Developer-first encrypted secrets CLI with automatic environment activation and portable team sharing.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages