@akshxy/envgit 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/package.json +4 -3
- package/src/commands/add-env.js +3 -3
- package/src/commands/get.js +2 -2
- package/src/commands/import.js +3 -5
- package/src/commands/switch.js +0 -26
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# envgit
|
|
2
|
+
|
|
3
|
+
Encrypted per-project environment variable manager. Store secrets safely alongside your code — encrypted at rest, never in plaintext.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm install -g @akshxy/envgit
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
`.env` files get committed by accident. `envgit` keeps your secrets encrypted in `.envgit/` so you can safely commit them to git and share them with your team — only people with the key can decrypt them.
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 1. Initialize in your project
|
|
17
|
+
envgit init
|
|
18
|
+
|
|
19
|
+
# 2. Set some variables
|
|
20
|
+
envgit set API_KEY=abc123 DB_PASS=secret
|
|
21
|
+
|
|
22
|
+
# 3. Commit the encrypted store (not the key!)
|
|
23
|
+
git add .envgit/
|
|
24
|
+
git commit -m "add encrypted env"
|
|
25
|
+
|
|
26
|
+
# 4. Share your key with teammates
|
|
27
|
+
envgit keygen --show
|
|
28
|
+
# → teammate runs: envgit keygen --set <key>
|
|
29
|
+
|
|
30
|
+
# 5. Write .env when you need it locally
|
|
31
|
+
envgit unpack dev
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Commands
|
|
35
|
+
|
|
36
|
+
### Key management
|
|
37
|
+
|
|
38
|
+
| Command | Description |
|
|
39
|
+
|---------|-------------|
|
|
40
|
+
| `envgit init` | Initialize in current project, generates key |
|
|
41
|
+
| `envgit keygen` | Generate a new key and save it |
|
|
42
|
+
| `envgit keygen --show` | Print current key for sharing with teammates |
|
|
43
|
+
| `envgit keygen --set <key>` | Save a key received from a teammate |
|
|
44
|
+
| `envgit rotate-key` | Generate new key, re-encrypt all environments |
|
|
45
|
+
| `envgit verify` | Check all environments decrypt correctly |
|
|
46
|
+
|
|
47
|
+
### Variables
|
|
48
|
+
|
|
49
|
+
| Command | Description |
|
|
50
|
+
|---------|-------------|
|
|
51
|
+
| `envgit set KEY=VALUE ...` | Set one or more variables |
|
|
52
|
+
| `envgit get KEY` | Print a single value |
|
|
53
|
+
| `envgit delete KEY` | Remove a variable |
|
|
54
|
+
| `envgit rename OLD NEW` | Rename a variable |
|
|
55
|
+
| `envgit list` | List all keys in active environment |
|
|
56
|
+
| `envgit list --show-values` | List keys and values |
|
|
57
|
+
|
|
58
|
+
### Environments
|
|
59
|
+
|
|
60
|
+
| Command | Description |
|
|
61
|
+
|---------|-------------|
|
|
62
|
+
| `envgit envs` | List all environments with variable counts |
|
|
63
|
+
| `envgit add-env <name>` | Create a new environment |
|
|
64
|
+
| `envgit unpack <env>` | Decrypt env and write `.env` file |
|
|
65
|
+
| `envgit copy KEY --from dev --to prod` | Copy a variable between environments |
|
|
66
|
+
| `envgit diff dev prod` | Show differences between two environments |
|
|
67
|
+
| `envgit diff dev prod --show-values` | Include values in diff |
|
|
68
|
+
|
|
69
|
+
### Export & run
|
|
70
|
+
|
|
71
|
+
| Command | Description |
|
|
72
|
+
|---------|-------------|
|
|
73
|
+
| `envgit export` | Print as `KEY=VALUE` lines (pipeable) |
|
|
74
|
+
| `envgit export --format json` | Print as JSON |
|
|
75
|
+
| `envgit export --format shell` | Print as `export KEY="VALUE"` (eval-able) |
|
|
76
|
+
| `envgit run -- node server.js` | Run a command with env vars injected |
|
|
77
|
+
| `envgit import --file .env.local` | Encrypt an existing `.env` file |
|
|
78
|
+
|
|
79
|
+
### Status
|
|
80
|
+
|
|
81
|
+
| Command | Description |
|
|
82
|
+
|---------|-------------|
|
|
83
|
+
| `envgit status` | Show project, active env, key source, .env state |
|
|
84
|
+
|
|
85
|
+
## All options support `--env <name>`
|
|
86
|
+
|
|
87
|
+
Most commands default to the active environment. Pass `--env` to target a specific one:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
envgit set API_KEY=prod-key --env prod
|
|
91
|
+
envgit list --env staging
|
|
92
|
+
envgit export --env prod --format json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Team workflow
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Developer A (project owner)
|
|
99
|
+
envgit init
|
|
100
|
+
envgit set DB_URL=postgres://... API_KEY=...
|
|
101
|
+
git add .envgit/ && git commit -m "encrypted env"
|
|
102
|
+
envgit keygen --show # share this key securely with teammates
|
|
103
|
+
|
|
104
|
+
# Developer B (teammate)
|
|
105
|
+
git clone <repo>
|
|
106
|
+
envgit keygen --set <key-from-teammate>
|
|
107
|
+
envgit unpack dev # writes .env
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Security
|
|
111
|
+
|
|
112
|
+
- **AES-256-GCM** — authenticated encryption, tamper-proof
|
|
113
|
+
- **32-byte random key** from OS cryptographic RNG
|
|
114
|
+
- **Fresh random IV** per encryption — same value encrypts differently each time
|
|
115
|
+
- **Key file locked to `0o600`** — unreadable by other users
|
|
116
|
+
- **Permission check on load** — errors if `.envgit.key` is world-readable
|
|
117
|
+
- **Key bytes zeroized** from memory immediately after use
|
|
118
|
+
|
|
119
|
+
The key (`~/.envgit.key`) is gitignored automatically. Never commit it.
|
|
120
|
+
|
|
121
|
+
## Environment variable
|
|
122
|
+
|
|
123
|
+
Set `ENVGIT_KEY` instead of using a key file — useful in CI:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
export ENVGIT_KEY=$(cat .envgit.key)
|
|
127
|
+
envgit export --format shell | source /dev/stdin
|
|
128
|
+
```
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akshxy/envgit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Encrypted per-project environment variable manager",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"envgit": "
|
|
7
|
+
"envgit": "bin/envgit.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
|
-
"src"
|
|
11
|
+
"src",
|
|
12
|
+
"README.md"
|
|
12
13
|
],
|
|
13
14
|
"license": "MIT",
|
|
14
15
|
"dependencies": {
|
package/src/commands/add-env.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { requireProjectRoot, loadKey } from '../keystore.js';
|
|
2
2
|
import { loadConfig, saveConfig } from '../config.js';
|
|
3
3
|
import { writeEncEnv } from '../enc.js';
|
|
4
|
+
import { ok, fatal } from '../ui.js';
|
|
4
5
|
|
|
5
6
|
export async function addEnv(name) {
|
|
6
7
|
const projectRoot = requireProjectRoot();
|
|
@@ -8,13 +9,12 @@ export async function addEnv(name) {
|
|
|
8
9
|
const config = loadConfig(projectRoot);
|
|
9
10
|
|
|
10
11
|
if (config.envs.includes(name)) {
|
|
11
|
-
|
|
12
|
-
process.exit(1);
|
|
12
|
+
fatal(`Environment '${name}' already exists.`);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
config.envs.push(name);
|
|
16
16
|
saveConfig(projectRoot, config);
|
|
17
17
|
writeEncEnv(projectRoot, name, key, {});
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
ok(`Added environment '${name}'`);
|
|
20
20
|
}
|
package/src/commands/get.js
CHANGED
|
@@ -2,6 +2,7 @@ import { requireProjectRoot, loadKey } from '../keystore.js';
|
|
|
2
2
|
import { resolveEnv } from '../config.js';
|
|
3
3
|
import { readEncEnv } from '../enc.js';
|
|
4
4
|
import { getCurrentEnv } from '../state.js';
|
|
5
|
+
import { fatal, label } from '../ui.js';
|
|
5
6
|
|
|
6
7
|
export async function get(key, options) {
|
|
7
8
|
const projectRoot = requireProjectRoot();
|
|
@@ -11,8 +12,7 @@ export async function get(key, options) {
|
|
|
11
12
|
const vars = readEncEnv(projectRoot, envName, encKey);
|
|
12
13
|
|
|
13
14
|
if (!(key in vars)) {
|
|
14
|
-
|
|
15
|
-
process.exit(1);
|
|
15
|
+
fatal(`Key '${key}' not found in ${label(envName)}`);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
console.log(vars[key]);
|
package/src/commands/import.js
CHANGED
|
@@ -5,6 +5,7 @@ import { resolveEnv } from '../config.js';
|
|
|
5
5
|
import { writeEncEnv } from '../enc.js';
|
|
6
6
|
import { readEnvFile } from '../envfile.js';
|
|
7
7
|
import { getCurrentEnv } from '../state.js';
|
|
8
|
+
import { ok, fatal, label, dim } from '../ui.js';
|
|
8
9
|
|
|
9
10
|
export async function importEnv(options) {
|
|
10
11
|
const projectRoot = requireProjectRoot();
|
|
@@ -13,15 +14,12 @@ export async function importEnv(options) {
|
|
|
13
14
|
|
|
14
15
|
const filePath = join(projectRoot, options.file);
|
|
15
16
|
if (!existsSync(filePath)) {
|
|
16
|
-
|
|
17
|
-
process.exit(1);
|
|
17
|
+
fatal(`File not found: ${options.file}`);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const vars = readEnvFile(filePath);
|
|
21
21
|
const count = Object.keys(vars).length;
|
|
22
22
|
|
|
23
23
|
writeEncEnv(projectRoot, envName, key, vars);
|
|
24
|
-
|
|
25
|
-
`Imported ${count} variable${count !== 1 ? 's' : ''} from ${options.file} into [${envName}]`
|
|
26
|
-
);
|
|
24
|
+
ok(`Imported ${count} variable${count !== 1 ? 's' : ''} from ${dim(options.file)} into ${label(envName)}`);
|
|
27
25
|
}
|
package/src/commands/switch.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
|
-
import { existsSync } from 'fs';
|
|
3
|
-
import { requireProjectRoot, loadKey } from '../keystore.js';
|
|
4
|
-
import { getEncPath } from '../config.js';
|
|
5
|
-
import { readEncEnv } from '../enc.js';
|
|
6
|
-
import { writeEnvFile } from '../envfile.js';
|
|
7
|
-
|
|
8
|
-
export async function switchEnv(envName) {
|
|
9
|
-
const projectRoot = requireProjectRoot();
|
|
10
|
-
const key = loadKey(projectRoot);
|
|
11
|
-
|
|
12
|
-
const encPath = getEncPath(projectRoot, envName);
|
|
13
|
-
if (!existsSync(encPath)) {
|
|
14
|
-
console.error(
|
|
15
|
-
`Error: Environment '${envName}' does not exist. Use 'envgit add-env ${envName}' to create it.`
|
|
16
|
-
);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const vars = readEncEnv(projectRoot, envName, key);
|
|
21
|
-
const dotenvPath = join(projectRoot, '.env');
|
|
22
|
-
writeEnvFile(dotenvPath, vars);
|
|
23
|
-
|
|
24
|
-
const count = Object.keys(vars).length;
|
|
25
|
-
console.log(`Switched to [${envName}] — wrote ${count} variable${count !== 1 ? 's' : ''} to .env`);
|
|
26
|
-
}
|