@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 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.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Encrypted per-project environment variable manager",
5
5
  "type": "module",
6
6
  "bin": {
7
- "envgit": "./bin/envgit.js"
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": {
@@ -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
- console.error(`Error: Environment '${name}' already exists.`);
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
- console.log(`Added environment '${name}'.`);
19
+ ok(`Added environment '${name}'`);
20
20
  }
@@ -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
- console.error(`Error: Key '${key}' not found in [${envName}]`);
15
- process.exit(1);
15
+ fatal(`Key '${key}' not found in ${label(envName)}`);
16
16
  }
17
17
 
18
18
  console.log(vars[key]);
@@ -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
- console.error(`Error: File not found: ${options.file}`);
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
- console.log(
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
  }
@@ -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
- }