Skip to content

Commit 13ab80e

Browse files
committed
2 parents 212efc1 + a1fd930 commit 13ab80e

1 file changed

Lines changed: 164 additions & 47 deletions

File tree

README.md

Lines changed: 164 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,190 +1,305 @@
11
# Enveil
22

3-
Enveil keeps your environment variables encrypted and out of your filesystem.
3+
Enveil keeps your environment variables encrypted and out of your filesystem — for individuals and teams.
44

5-
Instead of storing secrets in `.env` files that can be accidentally committed, leaked, or read by anyone with filesystem access, Enveil stores everything in an encrypted vault and injects variables directly into processes at runtime — without ever writing them to disk.
5+
Most developers store secrets in `.env` files. Those files get accidentally committed to version control, shared over Slack, read by AI coding tools with filesystem access, and left behind on old machines. Enveil eliminates the file entirely. Secrets live in an encrypted vault and are injected directly into your process at runtime — they never touch disk as plaintext, not even temporarily.
6+
7+
For teams, Enveil goes further: a self-hosted server lets every developer share the same encrypted secrets without `.env` files, chat messages, or shared drives. One developer sets a variable; everyone else has it immediately.
68

79
## How it works
810

9-
Enveil uses a SQLCipher-encrypted SQLite vault stored at `~/.enveil/vault.db`. The master key never touches disk — it lives only in memory while the daemon is running, or is derived fresh from your password on each command. Variables are organized by project and environment, making it easy to manage development, staging, and production secrets separately.
11+
When you run `enveil run npm run dev`, Enveil:
12+
13+
1. Derives a 256-bit key from your master password using **Argon2id** (64MB memory, 4 threads) — resistant to GPU and ASIC brute-force attacks
14+
2. Decrypts the **SQLCipher vault** at `~/.enveil/vault.db` — the entire file is encrypted with AES-256, including table names, project names, and variable names
15+
3. Reads the variables for the active project and environment
16+
4. Spawns your process with those variables injected via `syscall.Exec` — no temporary files, no subshells, no intermediate writes
17+
5. The master key lives only in memory for the duration of the command, then is gone
18+
19+
The vault file is opaque binary. Without the master password, it is indistinguishable from random noise.
1020

11-
For teams, Enveil includes a self-hosted server that centralizes secrets across developers. Variables are encrypted on the client before being sent to the server — the server never sees plaintext values.
21+
For teams using the server, values are encrypted on the client with AES-GCM before being sent over the network. The server stores and returns ciphertext only — it never sees plaintext values, even if you trust the server operator completely.
1222

1323
## Installation
1424

1525
### Linux and macOS
26+
1627
```bash
1728
curl -fsSL https://raw.githubusercontent.com/MaximoCoder/Enveil/main/install.sh | sh
1829
```
1930

20-
The installer automatically detects your OS and architecture, downloads the correct binary, verifies its checksum, and installs it to `/usr/local/bin`.
31+
The installer detects your OS and architecture, downloads the correct binary, verifies its checksum, and installs it to `/usr/local/bin`.
2132

2233
### Windows
2334

2435
Use [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) and run the Linux installer inside it.
2536

26-
### Install from source
37+
### From source
38+
39+
Requires Go 1.22+ and `libsqlcipher-dev` (Ubuntu/Debian) or `sqlcipher` (macOS).
2740

28-
Requires Go 1.22 or later and `libsqlcipher-dev` (Ubuntu/Debian) or `sqlcipher` (macOS).
2941
```bash
3042
go install github.com/MaximoCoder/Enveil/cli/cmd/enveil@latest
3143
```
3244

3345
### Shell integration
3446

35-
Add this to your `~/.zshrc` or `~/.bashrc` to automatically show the active project in your prompt when you navigate to a registered directory:
47+
Add this to your `~/.zshrc` or `~/.bashrc` to automatically show the active project and environment in your prompt when you navigate to a registered directory:
48+
3649
```bash
3750
eval "$(enveil shell-init)"
3851
```
3952

53+
## Quickstart
54+
55+
```bash
56+
# 1. Create your vault and set a master password (run once)
57+
enveil init
58+
59+
# 2. Register your project (run once per project directory)
60+
cd ~/projects/myapp
61+
enveil init
62+
63+
# 3. Import your existing .env file
64+
enveil import .env
65+
66+
# 4. Delete the .env file — you no longer need it
67+
rm .env
68+
69+
# 5. Run your app normally
70+
enveil run npm run dev
71+
```
72+
73+
From this point on, your secrets exist only in the encrypted vault.
74+
4075
## Usage
4176

4277
### First time setup
78+
4379
```bash
4480
enveil init
4581
```
4682

47-
Run this once to create your vault and set your master password. Then run it again inside any project directory to register it.
83+
Run this once globally to create your vault and set your master password. Run it again inside any project directory to register that project.
4884

4985
### Saving variables
86+
5087
```bash
5188
enveil set DATABASE_URL=postgres://localhost/mydb
5289
enveil set API_KEY=supersecret123
5390
```
5491

5592
### Importing from an existing .env file
93+
5694
```bash
5795
enveil import .env
5896
enveil import .env.local
5997
```
6098

61-
Imports all variables from the file into the active environment. Optionally deletes the original file after importing.
99+
Imports all variables from the file into the active environment. Enveil will ask if you want to delete the original file after importing.
62100

63101
### Running commands with variables injected
102+
64103
```bash
65104
enveil run npm run dev
66105
enveil run python manage.py runserver
106+
enveil run php artisan serve
67107
enveil run printenv DATABASE_URL
68108
```
69109

70-
Variables are injected into the process environment. No `.env` file is created or written to disk.
110+
Variables are injected directly into the process environment. No `.env` file is created or written to disk at any point.
71111

72112
### Getting and listing variables
113+
73114
```bash
74-
enveil list # show all variable names (values are masked)
115+
enveil list # show all variable names (values are masked by default)
75116
enveil get DATABASE_URL # get the value of a specific variable
76117
```
77118

78119
### Deleting variables
120+
79121
```bash
80122
enveil delete API_KEY
81123
```
82124

83125
Asks for confirmation before deleting.
84126

85127
### Managing environments
128+
129+
Each project can have multiple environments. Enveil creates `development` by default.
130+
86131
```bash
87-
enveil env list # list all environments
132+
enveil env list # list all environments in the current project
88133
enveil env add staging # create a new environment
89-
enveil env use staging # switch active environment
134+
enveil env add production
135+
enveil env use staging # switch the active environment
90136
```
91137

138+
All `set`, `get`, `list`, `run`, and `import` commands operate on the active environment. Switching environments is instant — no files to copy or rename.
139+
92140
### Comparing environments
141+
93142
```bash
94143
enveil diff development staging
95144
```
96145

97-
Shows which variables are missing, extra, or have different values between two environments — without revealing the values.
146+
Shows which variables are missing, extra, or have different values between two environments — without revealing the actual values. Useful for catching configuration drift before a deployment.
98147

99148
### Exporting a temporary .env file
149+
100150
```bash
101151
enveil export
102152
```
103153

104-
For tools that require a physical `.env` file. Automatically adds `.env` to `.gitignore`. Delete it when done.
154+
For tools that require a physical `.env` file. Automatically adds `.env` to `.gitignore`. Delete it when done — the vault is your source of truth.
105155

106156
### Managing projects
157+
107158
```bash
108-
enveil projects # list all registered projects
109-
enveil unregister # remove the current project from the vault
159+
enveil projects # list all registered project directories
160+
enveil unregister # remove the current directory from the vault
110161
```
111162

112163
### Git hook
164+
113165
```bash
114166
enveil hook install
115167
```
116168

117-
Installs a pre-commit hook that scans staged files for secrets before every commit. Detects known secret formats (AWS keys, Stripe keys, GitHub tokens, connection strings, private keys) and high-entropy strings using Shannon entropy analysis.
169+
Installs a pre-commit hook that scans staged files for secrets before every commit. It detects known secret formats (AWS keys, Stripe keys, GitHub tokens, connection strings, private keys) and high-entropy strings using Shannon entropy analysis.
118170

119171
Files like `.env` and `.env.local` are always blocked. Files like `.env.example` and `.env.template` are allowed since they are intended to contain placeholder values.
120172

121173
To bypass the hook when you are sure a file is safe:
174+
122175
```bash
123176
ENVEIL_SKIP=1 git commit
124177
```
125178

126-
To bypass all hooks entirely:
179+
To bypass all hooks:
180+
127181
```bash
128182
git commit --no-verify
129183
```
130184

131185
### Daemon
132186

133187
The daemon keeps your master key in memory so you do not have to type your password on every command.
188+
189+
```bash
190+
enveil daemon start # start the daemon, enter your password once
191+
enveil daemon status # check if the daemon is running
192+
enveil daemon stop # stop the daemon — the key is removed from memory immediately
193+
```
194+
195+
The daemon is optional. Without it, Enveil derives the key fresh from your password on each command. With it, you type your password once per session.
196+
197+
The key is never written to disk — the daemon holds it in a Unix socket at `~/.enveil/daemon.sock`, accessible only to your user.
198+
199+
## Security verification
200+
201+
You can verify Enveil's security properties manually without trusting the source code.
202+
203+
### 1. Confirm the vault is opaque
204+
205+
After running `enveil init` and setting a variable:
206+
207+
```bash
208+
xxd ~/.enveil/vault.db | head -5
209+
strings ~/.enveil/vault.db
210+
```
211+
212+
`xxd` will show binary data. `strings` will return nothing — there are no readable strings to extract. Every byte, including table names and variable names, is encrypted.
213+
214+
### 2. Confirm the wrong password is rejected
215+
216+
```bash
217+
enveil daemon stop # make sure the daemon is not caching your key
218+
enveil list # enter the wrong password
219+
```
220+
221+
Enveil will refuse to open the vault and return an error. The data is never partially exposed.
222+
223+
### 3. Confirm variables are never written to disk during injection
224+
225+
```bash
226+
# Run a command and check that no .env file was created
227+
enveil run printenv DATABASE_URL
228+
ls -la .env 2>/dev/null || echo "no .env file — correct"
229+
```
230+
231+
### 4. Confirm file permissions
232+
134233
```bash
135-
enveil daemon start # start daemon, enter password once
136-
enveil daemon status # check if daemon is running
137-
enveil daemon stop # stop daemon, key is removed from memory
234+
ls -la ~/.enveil/vault.db
138235
```
139236

140-
The daemon is optional. Without it, Enveil asks for your password on each command.
237+
The vault is created with `0600` permissions — readable and writable only by your user, not by other users on the same machine.
141238

142239
## Team server
143240

144-
The Enveil server allows teams to share encrypted secrets across developers without relying on `.env` files, chat messages, or shared drives.
241+
The Enveil server lets teams share encrypted secrets across developers without relying on `.env` files, chat messages, or shared drives. It is self-hosted — your secrets never leave your infrastructure.
145242

146243
### How it works
147244

148-
The server stores all variables encrypted. Values are encrypted on the client before being sent over the network — the server never sees plaintext values. Even if the server is compromised, secrets remain unreadable without the API key.
245+
Values are encrypted on the client with AES-GCM before being sent to the server. The server stores and returns ciphertext only. Even if someone gains access to the server machine or the server vault file, they cannot read the secrets without the API key used to encrypt them.
149246

150-
### Installing the server
247+
### Setting up the server
151248

152249
Download the server binary from the [latest release](https://github.com/MaximoCoder/Enveil/releases/latest) for your platform (`enveil-server-linux-amd64`, `enveil-server-darwin-arm64`, etc.) and place it in your PATH.
153250

154-
### Running the server
155251
```bash
156252
ENVEIL_API_KEY=your-secret-key \
157253
ENVEIL_VAULT_PASSWORD=your-vault-password \
158254
ENVEIL_PORT=8080 \
159255
enveil-server
160256
```
161257

162-
The server stores its vault at `~/.enveil-server/vault.db` by default. You can override this with `ENVEIL_VAULT_PATH`.
258+
The server stores its vault at `~/.enveil-server/vault.db` by default. Override with `ENVEIL_VAULT_PATH`.
163259

164260
For production, put the server behind a reverse proxy like nginx with HTTPS enabled.
165261

166-
### Connecting the CLI to the server
262+
### Team workflow
263+
264+
**Admin (one time):**
265+
167266
```bash
168-
enveil server connect http://your-server:8080 --key your-secret-key
267+
# Start the server
268+
ENVEIL_API_KEY=shared-api-key ENVEIL_VAULT_PASSWORD=vault-pass ENVEIL_PORT=8080 enveil-server
269+
270+
# Connect your own CLI to it
271+
enveil server connect http://your-server:8080 --key shared-api-key
272+
273+
# Register your project on the server
274+
cd ~/projects/myapp
275+
enveil init
276+
277+
# Import your existing secrets
278+
enveil import .env
169279
```
170280

171-
Once connected, all CLI commands use the server instead of the local vault. The connection settings are saved in `~/.enveil/config.json`.
281+
**Each developer (one time):**
282+
172283
```bash
173-
enveil server status # check connection
174-
enveil server disconnect # switch back to local vault
284+
# Connect to the server
285+
enveil server connect http://your-server:8080 --key shared-api-key
286+
287+
# Associate their local directory with the shared project
288+
cd ~/projects/myapp
289+
enveil server use-project myapp
175290
```
176291

177-
### Team workflow
292+
From that point, all `set`, `get`, `list`, `run`, `import`, `export`, `diff`, and `env` commands operate against the shared server. Variables set by one developer are immediately available to all others. No `.env` files are shared, committed, or sent over chat.
293+
294+
**Checking server status:**
178295

179-
The admin sets up the server once and shares the server URL and API key with the team. Each developer runs:
180296
```bash
181-
enveil server connect http://192.168.1.100:8080 --key shared-api-key
182-
enveil init
297+
enveil server status # verify connection
298+
enveil server disconnect # switch back to local vault
183299
```
184300

185-
From that point, all `set`, `get`, `list`, `run`, `import`, `export`, `diff`, and `env` commands operate against the shared server. Variables set by one developer are immediately available to all others.
186-
187301
## Project structure
302+
188303
```
189304
~/.enveil/
190305
vault.db # SQLCipher encrypted database (local mode)
@@ -199,13 +314,15 @@ From that point, all `set`, `get`, `list`, `run`, `import`, `export`, `diff`, an
199314

200315
## Security model
201316

202-
- **Vault encryption**: AES-256 via SQLCipher. The entire database file is encrypted, including table names, project names, and variable names.
203-
- **Key derivation**: Argon2id with 64MB memory, 4 threads. Resistant to GPU and ASIC brute-force attacks.
204-
- **Master key**: Never written to disk. Lives in memory only while the daemon is running.
205-
- **Transport encryption**: Values are encrypted with AES-GCM on the client before being sent to the server. The server stores and returns ciphertext only.
206-
- **File permissions**: Vault and config files are created with `0600` permissions (owner read/write only).
207-
- **Process injection**: Variables are passed directly to child process environments via `syscall.Exec`, never written to temporary files.
208-
- **Secret scanning**: Pre-commit hook combines pattern matching and Shannon entropy analysis to catch secrets before they reach version control.
317+
| Property | Implementation |
318+
|---|---|
319+
| Vault encryption | AES-256 via SQLCipher. The entire database is encrypted, including metadata. |
320+
| Key derivation | Argon2id, 64MB memory, 4 threads. Resistant to GPU and ASIC attacks. |
321+
| Master key at rest | Never written to disk. Held in memory by the daemon, or derived per-command and discarded. |
322+
| Transport encryption | AES-GCM on the client before transmission. The server never sees plaintext. |
323+
| File permissions | Vault and config created with `0600` — owner only. |
324+
| Process injection | Variables passed via `syscall.Exec`, never through temporary files or environment exports. |
325+
| Secret scanning | Pre-commit hook uses pattern matching and Shannon entropy analysis. |
209326

210327
## License
211328

0 commit comments

Comments
 (0)