@captainsafia/burrow 1.0.0-preview.0d335f8 → 1.0.0-preview.285f965

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 CHANGED
@@ -1,6 +1,10 @@
1
1
  # burrow
2
2
 
3
- A platform-agnostic, directory-scoped secrets manager. Store secrets outside your repos, inherit them through directory ancestry.
3
+ Burrow is a platform-agnostic, directory-scoped secrets manager. Secrets are stored outside your repos in a local SQLite store and exportable to various formats via the CLI. For a nicer dev experience, Burrow currently stores secrets in a plain-text format outside the target repo, which means that secrets can still be leaked to other users on your machine or people who gain access to your device. But, for your day-to-day dev use, this beats keeping secrets in gitignored files in your repo.
4
+
5
+ <p align="center">
6
+ <img src="demo.gif" alt="burrow demo" width="600">
7
+ </p>
4
8
 
5
9
  ```
6
10
  ~/projects/ # DATABASE_URL, API_KEY defined here
@@ -30,8 +34,10 @@ burrow set DATABASE_URL=postgres://localhost/mydb --path ~/projects
30
34
  ### Get a secret
31
35
 
32
36
  ```bash
33
- burrow get API_KEY --show
37
+ burrow get API_KEY
34
38
  burrow get API_KEY --format json
39
+ # Redact the secret value in output
40
+ burrow get API_KEY --redact
35
41
  ```
36
42
 
37
43
  ### List all secrets
@@ -39,13 +45,21 @@ burrow get API_KEY --format json
39
45
  ```bash
40
46
  burrow list
41
47
  burrow list --format json
48
+ # Redact secret values in output
49
+ burrow list --redact
42
50
  ```
43
51
 
44
52
  ### Export to your shell
45
53
 
46
54
  ```bash
55
+ # Auto-detects your shell (bash, fish, powershell, cmd)
47
56
  eval "$(burrow export)"
48
- eval "$(burrow export --format shell)" && npm start
57
+
58
+ # Or specify a format explicitly
59
+ burrow export --format fish
60
+ burrow export --format powershell
61
+ burrow export --format dotenv
62
+ burrow export --format json
49
63
  ```
50
64
 
51
65
  ### Block inheritance
@@ -84,13 +98,26 @@ import { BurrowClient } from '@captainsafia/burrow';
84
98
 
85
99
  const client = new BurrowClient();
86
100
 
87
- await client.set('API_KEY', 'secret123', { path: '/my/project' });
101
+ try {
102
+ await client.set('API_KEY', 'secret123', { path: '/my/project' });
103
+
104
+ const secret = await client.get('API_KEY', { cwd: '/my/project/subdir' });
105
+ console.log(secret?.value); // 'secret123'
106
+ console.log(secret?.sourcePath); // '/my/project'
88
107
 
89
- const secret = await client.get('API_KEY', { cwd: '/my/project/subdir' });
90
- console.log(secret?.value); // 'secret123'
91
- console.log(secret?.sourcePath); // '/my/project'
108
+ const allSecrets = await client.list({ cwd: '/my/project' });
109
+ } finally {
110
+ client.close(); // Clean up database connection
111
+ }
112
+ ```
113
+
114
+ Or with TypeScript's `using` declarations for automatic cleanup:
92
115
 
93
- const allSecrets = await client.list({ cwd: '/my/project' });
116
+ ```typescript
117
+ {
118
+ using client = new BurrowClient();
119
+ await client.set('API_KEY', 'secret123');
120
+ } // Automatically cleaned up
94
121
  ```
95
122
 
96
123
  ## Contributing
package/dist/api.d.ts CHANGED
@@ -5,7 +5,7 @@ export interface ResolvedSecret {
5
5
  value: string;
6
6
  sourcePath: string;
7
7
  }
8
- export type ExportFormat = "shell" | "dotenv" | "json";
8
+ export type ExportFormat = "shell" | "bash" | "fish" | "powershell" | "cmd" | "dotenv" | "json";
9
9
  /**
10
10
  * Configuration options for creating a BurrowClient instance.
11
11
  */
@@ -21,7 +21,7 @@ export interface BurrowClientOptions {
21
21
  configDir?: string;
22
22
  /**
23
23
  * Custom filename for the secrets store.
24
- * Defaults to `store.json`.
24
+ * Defaults to `store.db`.
25
25
  */
26
26
  storeFileName?: string;
27
27
  /**
@@ -99,10 +99,6 @@ export interface ExportOptions {
99
99
  * - `json`: Exports as a JSON object
100
100
  */
101
101
  format?: ExportFormat;
102
- /**
103
- * Whether to show actual values (currently unused, reserved for future use).
104
- */
105
- showValues?: boolean;
106
102
  /**
107
103
  * Whether to include source paths in JSON output.
108
104
  * When true, JSON output includes `{ key: { value, sourcePath } }` format.
@@ -151,7 +147,7 @@ export declare class BurrowClient {
151
147
  * The secret will be available to the specified directory and all its
152
148
  * subdirectories, unless overridden or blocked at a deeper level.
153
149
  *
154
- * @param key - Environment variable name. Must match `^[A-Z_][A-Z0-9_]*$`
150
+ * @param key - Environment variable name. Must match `^[A-Za-z_][A-Za-z0-9_]*$`
155
151
  * @param value - Secret value to store
156
152
  * @param options - Set options including target path
157
153
  * @throws Error if the key format is invalid
@@ -215,7 +211,7 @@ export declare class BurrowClient {
215
211
  *
216
212
  * A blocked key can be re-enabled by calling `set` at the same or deeper path.
217
213
  *
218
- * @param key - Environment variable name to block. Must match `^[A-Z_][A-Z0-9_]*$`
214
+ * @param key - Environment variable name to block. Must match `^[A-Za-z_][A-Za-z0-9_]*$`
219
215
  * @param options - Block options including target path
220
216
  * @throws Error if the key format is invalid
221
217
  *
@@ -240,7 +236,7 @@ export declare class BurrowClient {
240
236
  * `remove` completely deletes the secret entry. After removal, the key
241
237
  * may still be inherited from parent directories if defined there.
242
238
  *
243
- * @param key - Environment variable name to remove. Must match `^[A-Z_][A-Z0-9_]*$`
239
+ * @param key - Environment variable name to remove. Must match `^[A-Za-z_][A-Za-z0-9_]*$`
244
240
  * @param options - Remove options including target path
245
241
  * @returns true if the secret was found and removed, false if it didn't exist
246
242
  * @throws Error if the key format is invalid
package/dist/api.js CHANGED
@@ -66,10 +66,10 @@ class Storage {
66
66
  await chmod(this.configDir, 448);
67
67
  }
68
68
  this.db = new Database(this.storePath);
69
- this.db.run("PRAGMA journal_mode = WAL");
70
69
  if (!isWindows()) {
71
70
  await chmod(this.storePath, 384);
72
71
  }
72
+ this.db.run("PRAGMA journal_mode = WAL");
73
73
  this.db.run(`
74
74
  CREATE TABLE IF NOT EXISTS secrets (
75
75
  path TEXT NOT NULL,
@@ -122,7 +122,12 @@ class Storage {
122
122
  }
123
123
  async getAncestorPaths(canonicalPath) {
124
124
  const db = await this.ensureDb();
125
- const rows = db.query("SELECT DISTINCT path FROM secrets WHERE ? = path OR ? LIKE path || '/' || '%' OR path = '/'").all(canonicalPath, canonicalPath);
125
+ let rows;
126
+ if (isWindows()) {
127
+ rows = db.query("SELECT DISTINCT path FROM secrets WHERE ? = path OR ? LIKE path || '\\' || '%' OR (length(path) = 3 AND path LIKE '_:\\' AND ? LIKE path || '%')").all(canonicalPath, canonicalPath, canonicalPath);
128
+ } else {
129
+ rows = db.query("SELECT DISTINCT path FROM secrets WHERE ? = path OR ? LIKE path || '/' || '%' OR path = '/'").all(canonicalPath, canonicalPath);
130
+ }
126
131
  return rows.map((row) => row.path);
127
132
  }
128
133
  async removeKey(canonicalPath, key) {
@@ -246,6 +251,9 @@ function escapeShellValue(value) {
246
251
  function escapeDoubleQuotes(value) {
247
252
  return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
248
253
  }
254
+ function escapePowerShellValue(value) {
255
+ return value.replace(/'/g, "''");
256
+ }
249
257
  function formatShell(secrets) {
250
258
  const lines = [];
251
259
  const sortedKeys = Array.from(secrets.keys()).sort();
@@ -258,6 +266,42 @@ function formatShell(secrets) {
258
266
  return lines.join(`
259
267
  `);
260
268
  }
269
+ function formatFish(secrets) {
270
+ const lines = [];
271
+ const sortedKeys = Array.from(secrets.keys()).sort();
272
+ for (const key of sortedKeys) {
273
+ const secret = secrets.get(key);
274
+ assertValidEnvKey(key);
275
+ const escapedValue = escapeShellValue(secret.value);
276
+ lines.push(`set -gx ${key} '${escapedValue}'`);
277
+ }
278
+ return lines.join(`
279
+ `);
280
+ }
281
+ function formatPowerShell(secrets) {
282
+ const lines = [];
283
+ const sortedKeys = Array.from(secrets.keys()).sort();
284
+ for (const key of sortedKeys) {
285
+ const secret = secrets.get(key);
286
+ assertValidEnvKey(key);
287
+ const escapedValue = escapePowerShellValue(secret.value);
288
+ lines.push(`$env:${key} = '${escapedValue}'`);
289
+ }
290
+ return lines.join(`
291
+ `);
292
+ }
293
+ function formatCmd(secrets) {
294
+ const lines = [];
295
+ const sortedKeys = Array.from(secrets.keys()).sort();
296
+ for (const key of sortedKeys) {
297
+ const secret = secrets.get(key);
298
+ assertValidEnvKey(key);
299
+ const escapedValue = secret.value.replace(/([&|<>^])/g, "^$1");
300
+ lines.push(`set ${key}=${escapedValue}`);
301
+ }
302
+ return lines.join(`
303
+ `);
304
+ }
261
305
  function formatDotenv(secrets) {
262
306
  const lines = [];
263
307
  const sortedKeys = Array.from(secrets.keys()).sort();
@@ -295,7 +339,14 @@ function formatJson(secrets, includeSources = false) {
295
339
  function format(secrets, fmt, options = {}) {
296
340
  switch (fmt) {
297
341
  case "shell":
342
+ case "bash":
298
343
  return formatShell(secrets);
344
+ case "fish":
345
+ return formatFish(secrets);
346
+ case "powershell":
347
+ return formatPowerShell(secrets);
348
+ case "cmd":
349
+ return formatCmd(secrets);
299
350
  case "dotenv":
300
351
  return formatDotenv(secrets);
301
352
  case "json":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@captainsafia/burrow",
3
- "version": "1.0.0-preview.0d335f8",
3
+ "version": "1.0.0-preview.285f965",
4
4
  "description": "Platform-agnostic, directory-scoped secrets manager",
5
5
  "type": "module",
6
6
  "main": "dist/api.js",
@@ -51,6 +51,7 @@
51
51
  ],
52
52
  "license": "MIT",
53
53
  "dependencies": {
54
+ "clipboardy": "^5.0.2",
54
55
  "commander": "^14.0.2"
55
56
  }
56
57
  }