Skip to content

Latest commit

 

History

History
230 lines (162 loc) · 11.2 KB

File metadata and controls

230 lines (162 loc) · 11.2 KB

image

envapor

Transparent, Git-native encryption for your .env files. Values are encrypted on commit and restored on checkout, so only ciphertext ever lands in Git, with no change to how you use Git or load config.

License Release CI Stars


Jump to: Why · Install · Quick start · Usage · How it works · Security · CI/CD


Note

Built live, in one sitting. Envapor went from an empty repo to this working tool during a live build session - no script, no highlight reel (and one OBS crash 20 minutes in). Watch the full 2.5-hour recording:

Zero to shipped ›


Envapor transparently encrypts the values in your .env files inside Git. Plaintext is encrypted on commit and restored on checkout, so your working tree stays exactly as it is today while Git only ever stores ciphertext.

No .env.enc, no wrapper commands, no changes to how your app loads config. After a one-time setup you just use Git.

  # your working tree (.env)                 # what Git actually stores
  DATABASE_URL=postgres://user:pass@db/app   DATABASE_URL=ENC[v2:9f3a…]
  STRIPE_KEY=sk_live_51H8xY2…                STRIPE_KEY=ENC[v2:c17b…]
  APP_ENV=production # PUBLIC                APP_ENV=production # PUBLIC

Variable names stay readable, so the committed .env is its own manifest. No .env.example to maintain.


Tip

Ship faster with Automaze. We partner with founders to bring their vision to life, scale their business, and optimize for success. Visit Automaze to book a call ›


Contents

Features

Feature What you get Deep dive
Zero workflow change git add/commit/push/pull work unchanged after setup Quick start
One file A single .env, no parallel encrypted copy to keep in sync Usage
Readable diffs & clean merges Deterministic encryption, so only changed keys show up How it works
Git-native Clean/smudge filters plus a pre-commit guard, nothing at runtime How it works
Public values Mark readable values with a # PUBLIC comment, fails closed Usage
Single static binary macOS, Linux, Windows, no dependencies Install
Agent-ready Install as an Agent Skill for coding agents Agent skill

Why

  • Zero workflow change. git add/commit/push/pull work unchanged after setup.
  • One file. A single .env, no parallel encrypted copy to keep in sync.
  • Readable diffs & clean merges. Encryption is deterministic, so only variables you actually change show up in a diff, and edits to different keys merge without conflict.
  • Git-native. Built on Git clean/smudge filters plus a pre-commit guard. Nothing to run at runtime.
  • Single static binary. macOS, Linux, Windows. No dependencies.

Install

# macOS (Homebrew)
brew install automazeio/tap/envapor

# Linux
curl -fsSL https://raw.githubusercontent.com/automazeio/envapor/main/installers/install.sh | sh

# Windows (PowerShell)
irm https://raw.githubusercontent.com/automazeio/envapor/main/installers/install.ps1 | iex

# From source (Go)
git clone https://github.com/automazeio/envapor
cd envapor/src && go install .

Verify with envapor --version.

Quick start

# once per team: generate a shared key
envapor keygen team

# in a repo (new or freshly cloned)
envapor init team              # uses ~/.config/envapor/keys/team
# or import a key file from anywhere:
envapor init --pem /path/to/team.pem

# then just use git
git add .env
git commit -m "Add config"
git push

On clone, teammates run the same envapor init team (or envapor init --pem …) and Git decrypts .env in place. Same command provisions servers and CI, no manual copying of secrets.

Usage

Edit .env normally. Values are encrypted on commit and decrypted on checkout automatically.

Public values — anything you want left readable in Git is marked with a PUBLIC comment:

APP_ENV=production            # PUBLIC
API_URL=https://api.acme.com  # PUBLIC: browser endpoint

Parsing fails closed: a value is left in plaintext only on an unambiguous # PUBLIC marker. Anything ambiguous is encrypted.

Managed files — .env and every .env.* variant are managed by default (.env.local, .env.production, …). Template files (.env.example, .env.sample, .env.template) are always excluded. Coverage is written to .gitattributes by envapor init.

Commands

Command Purpose
envapor keygen NAME Generate a new key at ~/.config/envapor/keys/NAME
envapor keys List stored keys, marking the current repository's key
envapor init NAME or --pem PATH Configure filters, hook, .gitattributes, and map the repo to a key (by stored name or key file)
envapor doctor Diagnose the setup (filters, hook, mapping, coverage, crypto round-trip)
envapor verify Check that .env files stored in Git contain no plaintext secrets (CI / pre-push)
envapor status Show the mapping and per-file encryption state
envapor migrate OLDKEY NEWKEY Re-encrypt managed values from one key to another (names or PEM paths)
envapor encrypt / decrypt Manually transform managed files (rarely needed)
envapor install-git-shim Enable git envapor … as a Git subcommand

The installers enable git envapor <command> automatically; with Homebrew or go install, run envapor install-git-shim once to add the shim next to the binary.

How it works

Git clean/smudge filters do the work: the clean filter encrypts values on the way into the object store; the smudge filter decrypts them on checkout. A pre-commit hook is a safety net that aborts the commit if any non-PUBLIC value would reach Git as plaintext (for example, before filters are installed on a fresh clone).

Each value is encrypted independently with AES-256-GCM, using encryption/MAC subkeys derived from your 512-bit master key via HKDF. Encryption is deterministic (SIV-style: the nonce is derived from the variable name and the plaintext), which keeps diffs readable and merges clean. Each token is also bound to its variable name, so a ciphertext moved to a different variable fails to decrypt rather than silently supplying the wrong secret. Tokens are versioned (ENC[v2:…]) so the format can evolve; older v1 tokens remain readable.

Security

Read this before adopting Envapor. It makes explicit trade-offs.

  • Trust model. The master key is symmetric and shared. Every key holder can decrypt everything. Envapor is for trusted teams sharing a repo, not fine-grained or per-secret access control.
  • Deterministic encryption leaks equality. The same value under the same key and variable name always yields the same ciphertext. Anyone with read access to the encrypted repo (no key needed) can tell whether a value is unchanged across commits or whether the same variable holds the same value in two files. This is the deliberate cost of clean diffs and merges. If value-equality leakage is unacceptable for you, Envapor is the wrong tool.
  • Keys never touch the repo. They live under ~/.config/envapor/keys/ and repo→key mappings are stored locally. Distribute keys over a secure channel (e.g., a password manager), and never commit them.
  • Key rotation ≠ secret rotation. envapor migrate re-encrypts the working tree and future commits under a new key. It does not rewrite history: past commits stay encrypted under the old key, so anyone holding the old key and an old clone can still read that history. After a compromise, you must also rotate the affected secrets at their source (DB passwords, API keys). Envapor changes the lock; it can't recall copies that have already been distributed.
  • Offboarding is on you. When someone leaves, rotate the affected secrets and re-issue the key. Envapor doesn't manage this.

Envapor is not a replacement for HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or Google Secret Manager. It targets repository-based secret sharing, and complements those systems rather than competing with them.

CI/CD

A first-party GitHub Action installs Envapor, imports the key, configures filters, and decrypts the repo:

- uses: automazeio/setup-envapor@v1
  with:
    key: ${{ secrets.ENVAPOR_KEY }}
- run: go test ./...

Store the PEM contents in your CI provider's encrypted secrets.

To guard against plaintext secrets slipping into Git without needing the key, add envapor verify. It inspects the committed (index) content of managed .env files and exits non-zero if any non-PUBLIC value is still plaintext:

- run: envapor verify

Agent skill

Coding agents (Claude Code, or anything that supports Agent Skills) can install Envapor's skill and then set up, operate, and troubleshoot Envapor on their own — including the guardrails (never commit keys, never gitignore .env):

mkdir -p ~/.claude/skills/envapor
curl -fsSL https://raw.githubusercontent.com/automazeio/envapor/main/skills/envapor/SKILL.md \
  -o ~/.claude/skills/envapor/SKILL.md

The skill source lives in skills/envapor/SKILL.md.

Project layout

envapor/
├── src/
│   ├── internal/
│   │   ├── cmd/        # CLI subcommands (init, keygen, doctor, verify, …)
│   │   ├── config/     # Key store and repo→key mapping
│   │   ├── crypto/     # AES-256-GCM, HKDF, token format
│   │   ├── envfile/    # .env parsing and PUBLIC marker handling
│   │   ├── gitutil/    # Filters, hooks, .gitattributes
│   │   └── pktline/    # Git filter protocol
│   └── main.go         # Binary entry point
├── installers/         # install.sh, install.ps1
├── skills/envapor/     # Agent Skill (SKILL.md)
├── docs/               # User guide
├── .github/            # CI workflows and setup-envapor action
└── README.md

Documentation

Full walkthrough, team/server/CI workflows, and troubleshooting live in docs/user-guide.md.

License

Apache-2.0 © Automaze


Built with Go · Git clean/smudge filters · AES-256-GCM